Completed
Push — master ( 2a3874...7f6883 )
by Egor
01:39
created

collect_statistics()   B

Complexity

Conditions 5

Size

Total Lines 17

Duplication

Lines 0
Ratio 0 %
Metric Value
dl 0
loc 17
cc 5
rs 8.5454
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
from builtins import range
22
23
from functools import partial
24
from datetime import datetime, timedelta
25
26
from django.conf import settings
27
from django.db import transaction
28
from django.utils import timezone
29
from bitmapist import setup_redis, mark_event, WeekEvents, MonthEvents, DayEvents
30
31
from omaha.utils import get_id, valuedispatch
32
from omaha.settings import DEFAULT_CHANNEL
33
from omaha.models import ACTIVE_USERS_DICT_CHOICES, Request, AppRequest, Os, Hw, Event, Version, Channel
34
35
__all__ = ['userid_counting', 'is_user_active']
36
37
host, port, db = settings.CACHES['statistics']['LOCATION'].split(':')
38
setup_redis('default', host, port, db=db)
39
40
41
def userid_counting(userid, apps_list, platform, now=None):
42
    id = get_id(userid)
43
    mark_event('request', id, now=now)
44
    list(map(partial(add_app_statistics, id, platform, now=now), apps_list or []))
45
46
47
def add_app_statistics(userid, platform, app, now=None):
48
    mark = partial(mark_event, now=now)
49
    appid = app.get('appid')
50
    version = app.get('version')
51
    channel = app.get('tag') or DEFAULT_CHANNEL
52
    mark('request:%s' % appid, userid)
53
    mark('request:{}:{}'.format(appid, version), userid)
54
    mark('request:{}:{}'.format(appid, platform), userid)
55
    mark('request:{}:{}'.format(appid, channel), userid)
56
    mark('request:{}:{}:{}'.format(appid, platform, version), userid)
57
58
59
def get_users_statistics_months(app_id=None):
60
    now = timezone.now()
61
    year = now.year
62
    event_name = 'request:%s' % app_id if app_id else 'request'
63
64
    months = []
65
    for m in range(1, 13):
66
        months.append(MonthEvents(event_name, year, m))
67
    data = [(datetime(year, i+1, 1).strftime("%B"), len(e)) for i, e in enumerate(months)]
68
    return data
69
70
71
def get_users_statistics_weeks(app_id=None):
72
    now = timezone.now()
73
    event_name = 'request:%s' % app_id if app_id else 'request'
74
    year = now.year
75
    current_week = now.isocalendar()[1]
76
    previous_week = (now - timedelta(weeks=1)).isocalendar()[1]
77
    yesterday = now - timedelta(days=1)
78
    data = [
79
        ('Previous week', len(WeekEvents(event_name, year, previous_week))),
80
        ('Current week', len(WeekEvents(event_name, year, current_week))),
81
        ('Yesterday', len(DayEvents(event_name, year, yesterday.month, yesterday.day))),
82
        ('Today', len(DayEvents(event_name, year, now.month, now.day))),
83
    ]
84
    return data
85
86
87
def get_channel_statistics(app_id):
88
    now = timezone.now()
89
    event_name = 'request:{}:{}'
90
    week = now.isocalendar()[1]
91
    channels = [c.name for c in Channel.objects.all()]
92
    data = [(channel, len(WeekEvents(event_name.format(app_id, channel), now.year, week))) for channel in channels]
93
    return data
94
95
96
def get_users_versions(app_id):
97
    now = timezone.now()
98
    event_name = 'request:{}:{}'
99
    week = now.isocalendar()[1]
100
    versions = [str(v.version) for v in Version.objects.filter_by_enabled(app__id=app_id)]
101
    data = [(v, len(WeekEvents(event_name.format(app_id, v), now.year, week))) for v in versions]
102
    return data
103
104
105
@valuedispatch
106
def is_user_active(period, userid):
107
    return False
108
109
110
@is_user_active.register(ACTIVE_USERS_DICT_CHOICES['all'])
111
def _(period, userid):
112
    return True
113
114
115
@is_user_active.register(ACTIVE_USERS_DICT_CHOICES['week'])
116
def _(period, userid):
117
    return get_id(userid) in WeekEvents.from_date('request', timezone.now())
118
119
120
@is_user_active.register(ACTIVE_USERS_DICT_CHOICES['month'])
121
def _(period, userid):
122
    return get_id(userid) in MonthEvents.from_date('request', timezone.now())
123
124
125
def get_kwargs_for_model(cls, obj, exclude=None):
126
    exclude = exclude or []
127
    fields = [(field.name, field.to_python) for field in cls._meta.fields if field.name not in exclude]
128
    kwargs = dict([(i, convert(obj.get(i))) for (i, convert) in fields])
129
    return kwargs
130
131
132
def parse_os(os):
133
    kwargs = get_kwargs_for_model(Os, os, exclude=['id'])
134
    obj, flag = Os.objects.get_or_create(**kwargs)
135
    return obj
136
137
138
def parse_hw(hw):
139
    kwargs = get_kwargs_for_model(Hw, hw, exclude=['id'])
140
    obj, flag = Hw.objects.get_or_create(**kwargs)
141
    return obj
142
143
144
def parse_req(request, ip=None):
145
    kwargs = get_kwargs_for_model(Request, request, exclude=['os', 'hw', 'created', 'id'])
146
    kwargs['ip'] = ip
147
    return Request(**kwargs)
148
149
150
def parse_apps(apps, request):
151
    app_list = []
152
    for app in apps:
153
        events = app.findall('event')
154
155
        if not events:
156
            continue
157
158
        kwargs = get_kwargs_for_model(AppRequest, app, exclude=['request', 'version', 'nextversion', 'id'])
159
        kwargs['version'] = app.get('version') or None
160
        kwargs['nextversion'] = app.get('nextversion') or None
161
        app_req = AppRequest.objects.create(request=request, **kwargs)
162
        event_list = parse_events(events)
163
        app_req.events.add(*event_list)
164
        app_list.append(app_req)
165
    return app_list
166
167
168
def parse_events(events):
169
    res = []
170
    for event in events:
171
        kwargs = get_kwargs_for_model(Event, event)
172
        res.append(Event.objects.create(**kwargs))
173
    return res
174
175
176
@transaction.atomic
177
def collect_statistics(request, ip=None):
178
    userid = request.get('userid')
179
    apps = request.findall('app')
180
181
    if userid:
182
        userid_counting(userid, apps, request.os.get('platform'))
183
184
    if not filter(lambda app: bool(app.findall('event')), apps):
185
        return
186
187
    req = parse_req(request, ip)
188
    req.os = parse_os(request.os)
189
    req.hw = parse_hw(request.hw) if request.get('hw') else None
190
    req.save()
191
192
    parse_apps(apps, req)
193
194