1 | # coding: utf8 |
||
2 | |||
3 | """ |
||
4 | This software is licensed under the Apache 2 license, quoted below. |
||
5 | |||
6 | Copyright 2014 Crystalnix Limited |
||
7 | |||
8 | Licensed under the Apache License, Version 2.0 (the "License"); you may not |
||
9 | use this file except in compliance with the License. You may obtain a copy of |
||
10 | the License at |
||
11 | |||
12 | http://www.apache.org/licenses/LICENSE-2.0 |
||
13 | |||
14 | Unless required by applicable law or agreed to in writing, software |
||
15 | distributed under the License is distributed on an "AS IS" BASIS, WITHOUT |
||
16 | WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the |
||
17 | License for the specific language governing permissions and limitations under |
||
18 | the License. |
||
19 | """ |
||
20 | |||
21 | import datetime |
||
22 | |||
23 | from django.http import Http404 |
||
24 | from django.conf import settings |
||
25 | from django.utils import timezone |
||
26 | |||
27 | from rest_framework import viewsets |
||
28 | from rest_framework import mixins |
||
29 | from rest_framework import pagination |
||
30 | from rest_framework.views import APIView |
||
31 | from rest_framework.response import Response |
||
32 | |||
33 | import pytz |
||
34 | |||
35 | from omaha.statistics import ( |
||
36 | get_users_statistics_months, |
||
37 | get_users_versions, |
||
38 | get_channel_statistics, |
||
39 | get_users_live_versions |
||
40 | ) |
||
41 | from omaha.serializers import ( |
||
42 | AppSerializer, |
||
43 | DataSerializer, |
||
44 | PlatformSerializer, |
||
45 | ChannelSerializer, |
||
46 | VersionSerializer, |
||
47 | ActionSerializer, |
||
48 | StatisticsMonthsSerializer, |
||
49 | MonthRangeSerializer, |
||
50 | MonthInputSerializer, |
||
51 | ServerVersionSerializer, |
||
52 | LiveStatisticsInputSerializer, |
||
53 | PartialUpdateSerializer |
||
54 | ) |
||
55 | from omaha.models import ( |
||
56 | Application, |
||
57 | Data, |
||
58 | Platform, |
||
59 | Channel, |
||
60 | Version, |
||
61 | Action, |
||
62 | PartialUpdate |
||
63 | ) |
||
64 | from omaha.utils import get_month_range_from_dict |
||
65 | |||
66 | |||
67 | class BaseView(mixins.ListModelMixin, mixins.CreateModelMixin, |
||
68 | mixins.DestroyModelMixin, mixins.RetrieveModelMixin, |
||
69 | viewsets.GenericViewSet): |
||
70 | pass |
||
71 | |||
72 | |||
73 | class StandardResultsSetPagination(pagination.PageNumberPagination): |
||
74 | page_size = 10 |
||
75 | page_size_query_param = 'page_size' |
||
76 | max_page_size = 100 |
||
77 | |||
78 | |||
79 | class AppViewSet(viewsets.ModelViewSet): |
||
80 | """ |
||
81 | API endpoint that allows applications to be viewed. |
||
82 | |||
83 | ## Applications Collection |
||
84 | |||
85 | ### List all Applications [GET] |
||
86 | |||
87 | URL: `http://example.com/api/app/` |
||
88 | |||
89 | Response: |
||
90 | |||
91 | [ |
||
92 | { |
||
93 | "id": "{8A76FC95-0086-4BCE-9517-DC09DDB5652F}", |
||
94 | "name": "Chromium" |
||
95 | }, |
||
96 | { |
||
97 | "id": "{430FD4D0-B729-4F61-AA34-91526481799D}", |
||
98 | "name": "Potato" |
||
99 | } |
||
100 | ] |
||
101 | |||
102 | |||
103 | ### Create a Application [POST] |
||
104 | |||
105 | URL: `http://example.com/api/app/` |
||
106 | |||
107 | Headers: |
||
108 | |||
109 | Content-Type: application/json |
||
110 | |||
111 | Body: |
||
112 | |||
113 | { |
||
114 | "id": "{8A76FC95-0086-4BCE-9517-DC09DDB5652F}", |
||
115 | "name": "Chromium", |
||
116 | } |
||
117 | |||
118 | Response: |
||
119 | |||
120 | HTTP 201 CREATED |
||
121 | Content-Type: application/json |
||
122 | |||
123 | { |
||
124 | "id": "{8A76FC95-0086-4BCE-9517-DC09DDB5652F}", |
||
125 | "name": "Chromium", |
||
126 | } |
||
127 | |||
128 | ## Application |
||
129 | |||
130 | ### Retrieve a Application [GET] |
||
131 | |||
132 | URL: `http://example.com/api/app/[app_id]` |
||
133 | |||
134 | Response: |
||
135 | |||
136 | HTTP 201 CREATED |
||
137 | Content-Type: application/json |
||
138 | |||
139 | { |
||
140 | "id": "{8A76FC95-0086-4BCE-9517-DC09DDB5652F}", |
||
141 | "name": "Chromium", |
||
142 | } |
||
143 | |||
144 | ### Remove a Application [DELETE] |
||
145 | |||
146 | URL: `http://example.com/api/app/[app_id]` |
||
147 | |||
148 | Response: |
||
149 | |||
150 | HTTP 204 NO CONTENT |
||
151 | Content-Type: application/json |
||
152 | """ |
||
153 | queryset = Application.objects.all().order_by('-id') |
||
154 | serializer_class = AppSerializer |
||
155 | |||
156 | |||
157 | class PartialUpdateViewSet(viewsets.ModelViewSet): |
||
158 | queryset = PartialUpdate.objects.all().order_by('-id') |
||
159 | serializer_class = PartialUpdateSerializer |
||
160 | |||
161 | |||
162 | class DataViewSet(viewsets.ModelViewSet): |
||
163 | queryset = Data.objects.all().order_by('-id') |
||
164 | serializer_class = DataSerializer |
||
165 | |||
166 | |||
167 | class PlatformViewSet(viewsets.ModelViewSet): |
||
168 | queryset = Platform.objects.all().order_by('-id') |
||
169 | serializer_class = PlatformSerializer |
||
170 | |||
171 | |||
172 | class ChannelViewSet(viewsets.ModelViewSet): |
||
173 | queryset = Channel.objects.all().order_by('-id') |
||
174 | serializer_class = ChannelSerializer |
||
175 | |||
176 | |||
177 | class VersionViewSet(viewsets.ModelViewSet): |
||
178 | queryset = Version.objects.all().order_by('-id') |
||
179 | serializer_class = VersionSerializer |
||
180 | |||
181 | |||
182 | class ActionViewSet(viewsets.ModelViewSet): |
||
183 | queryset = Action.objects.all().order_by('-id') |
||
184 | serializer_class = ActionSerializer |
||
185 | |||
186 | |||
187 | class StatisticsMonthsDetailView(APIView): |
||
188 | MAC_KEYS = ['new', 'updates'] |
||
189 | OMAHA_KEYS = MAC_KEYS + ['uninstalls'] |
||
190 | |||
191 | def get_object(self, name): |
||
192 | try: |
||
193 | return Application.objects.get(name=name) |
||
194 | except Application.DoesNotExist: |
||
195 | raise Http404 |
||
196 | |||
197 | def get(self, request, app_name, format=None): |
||
198 | app = self.get_object(app_name) |
||
199 | dates = MonthRangeSerializer(data=request.GET) |
||
200 | dates.is_valid() |
||
201 | |||
202 | start, end = get_month_range_from_dict(dates.validated_data) |
||
203 | |||
204 | diapasons = [((start.month if year == start.year else 1, end.month if year == end.year else 12), year) |
||
205 | for year in range(start.year, end.year+1)] |
||
206 | |||
207 | data = {} |
||
208 | platforms = Platform.objects.values_list('name', flat=True) |
||
209 | for platform in platforms: |
||
210 | if platform == 'mac': |
||
211 | platform_keys = self.MAC_KEYS |
||
212 | else: |
||
213 | platform_keys = self.OMAHA_KEYS |
||
214 | platform_data = {key: [] for key in platform_keys} |
||
215 | for diapason in diapasons: |
||
216 | step = get_users_statistics_months(app_id=app.id, platform=platform, year=diapason[1], |
||
217 | start=diapason[0][0], end=diapason[0][1]) |
||
218 | for key in platform_data: |
||
219 | platform_data[key] += step[key] |
||
220 | data.update({platform: platform_data}) |
||
221 | |||
222 | serializer = StatisticsMonthsSerializer(dict(data=data)) |
||
223 | return Response(serializer.data) |
||
224 | |||
225 | View Code Duplication | class StatisticsVersionsView(APIView): |
|
0 ignored issues
–
show
Duplication
introduced
by
![]() |
|||
226 | def get_object(self, name): |
||
227 | try: |
||
228 | return Application.objects.get(name=name) |
||
229 | except Application.DoesNotExist: |
||
230 | raise Http404 |
||
231 | |||
232 | def get(self, request, app_name, format=None): |
||
233 | now = timezone.now() |
||
234 | app = self.get_object(app_name) |
||
235 | |||
236 | date = MonthInputSerializer(data=request.GET) |
||
237 | date.is_valid() |
||
238 | date = date.validated_data.get('date', now) |
||
239 | |||
240 | data = get_users_versions(app.id, date=date) |
||
241 | serializer = StatisticsMonthsSerializer(dict(data=dict(data))) |
||
242 | return Response(serializer.data) |
||
243 | |||
244 | |||
245 | class StatisticsVersionsLiveView(APIView): |
||
246 | def get_object(self, name): |
||
247 | try: |
||
248 | return Application.objects.get(name=name) |
||
249 | except Application.DoesNotExist: |
||
250 | raise Http404 |
||
251 | |||
252 | def get(self, request, app_name, format=None): |
||
253 | import logging |
||
254 | logging.info('Starting working in view') |
||
255 | app = self.get_object(app_name) |
||
256 | |||
257 | now = timezone.now() |
||
258 | data = LiveStatisticsInputSerializer(data=request.GET) |
||
259 | data.is_valid() |
||
260 | |||
261 | end = data.validated_data.get('end', now) |
||
262 | start = data.validated_data.get('start', end - datetime.timedelta(hours=24)) |
||
263 | channel = data.validated_data.get('channel') |
||
264 | |||
265 | data = get_users_live_versions(app.id, start, end, channel, tz=request.session.get('django_timezone', 'UTC')) |
||
266 | logging.info('Getting data is finished') |
||
267 | serializer = StatisticsMonthsSerializer(dict(data=dict(data))) |
||
268 | return Response(serializer.data) |
||
269 | |||
270 | |||
271 | View Code Duplication | class StatisticsChannelsView(APIView): |
|
0 ignored issues
–
show
|
|||
272 | def get_object(self, name): |
||
273 | try: |
||
274 | return Application.objects.get(name=name) |
||
275 | except Application.DoesNotExist: |
||
276 | raise Http404 |
||
277 | |||
278 | def get(self, request, app_name, format=None): |
||
279 | now = timezone.now() |
||
280 | app = self.get_object(app_name) |
||
281 | |||
282 | date = MonthInputSerializer(data=request.GET) |
||
283 | date.is_valid() |
||
284 | date = date.validated_data.get('date', now) |
||
285 | |||
286 | data = get_channel_statistics(app.id, date=date) |
||
287 | serializer = StatisticsMonthsSerializer(dict(data=dict(data))) |
||
288 | return Response(serializer.data) |
||
289 | |||
290 | |||
291 | class ServerVersionView(APIView): |
||
292 | def get(self, request, format=None): |
||
293 | version = settings.APP_VERSION |
||
294 | serializer = ServerVersionSerializer(dict(version=version)) |
||
295 | return Response(serializer.data) |
||
296 |