ManualCleanupFormView   A
last analyzed

Complexity

Total Complexity 7

Size/Duplication

Total Lines 34
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
dl 0
loc 34
rs 10
c 0
b 0
f 0
wmc 7

5 Methods

Rating   Name   Duplication   Size   Complexity  
A get_success_url() 0 2 1
A form_valid() 0 4 1
A get_context_data() 0 11 1
A get_form_class() 0 7 3
A get_initial() 0 2 1
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 logging
22
import datetime
23
import pytz
24
import json
25
from collections import OrderedDict
26
27
from django.contrib.admin.views.decorators import staff_member_required
28
from django.contrib import messages
29
from django.utils.decorators import method_decorator
30
from django.views.generic import DetailView, ListView, TemplateView
31
from django.views.generic.edit import FormView
32
from django_tables2 import SingleTableView
33
from django.core.urlresolvers import reverse_lazy, reverse
34
from django.shortcuts import get_object_or_404
35
from django.http import Http404
36
from django.core.cache import cache
37
38
from dynamic_preferences.forms import global_preference_form_builder
39
from dynamic_preferences_registry import global_preferences_manager as gpm
40
41
from omaha.models import Application, AppRequest, Version, Platform
42
from omaha.filters import AppRequestFilter
43
from omaha.utils import make_piechart, get_platforms_by_appid
44
from omaha.filters import EVENT_RESULT, EVENT_TYPE
45
from omaha.tables import AppRequestTable, VersionsUsageTable
46
from omaha.forms import CrashManualCleanupForm, ManualCleanupForm
47
from omaha.dynamic_preferences_registry import global_preferences
48
from sparkle.models import SparkleVersion
49
50
logger = logging.getLogger(__name__)
51
52
53
STATE_CANCELLED = {
54
    0: 'unknown',
55
    1: 'init',
56
    2: 'waiting to check for update',
57
    3: 'checking for update',
58
    4: 'update available',
59
    5: 'waiting to download',
60
    6: 'retrying download',
61
    7: 'downloading',
62
    8: 'download complete',
63
    9: 'extracting',
64
    10: 'applying differential patch',
65
    11: 'ready to install',
66
    12: 'waiting to install',
67
    13: 'installing',
68
    14: 'install complete',
69
    15: 'paused',
70
    16: 'no update',
71
    17: 'error',
72
}
73
74
75
class StaffMemberRequiredMixin(object):
76
    @method_decorator(staff_member_required)
77
    def dispatch(self, *args, **kwargs):
78
        return super(StaffMemberRequiredMixin, self).dispatch(*args, **kwargs)
79
80
81
class StatisticsView(StaffMemberRequiredMixin, ListView):
82
    template_name = "admin/omaha/statistics.html"
83
    model = Application
84
    context_object_name = "app_list"
85
86
87
class StatisticsDetailView(StaffMemberRequiredMixin, DetailView):
88
    model = Application
89
    template_name = 'admin/omaha/statistics_detail.html'
90
    context_object_name = 'app'
91
    success_url = reverse_lazy('omaha_statistics_detail')
92
93
    def get_object(self, queryset=None):
94
        return get_object_or_404(Application, name=self.kwargs.get('name'))
95
96
    def get_context_data(self, **kwargs):
97
        context = super(StatisticsDetailView, self).get_context_data(**kwargs)
98
99
        app = self.object
100
101
        first_omaha_version = Version.objects.all().filter(app=app).order_by('created').first()
102
        omaha_start_date = getattr(first_omaha_version, 'created', datetime.datetime(1970, 1, 1, tzinfo=pytz.UTC))
103
104
        first_mac_version = SparkleVersion.objects.all().filter(app=app).order_by('created').first()
105
        mac_start_date = getattr(first_mac_version, 'created', datetime.datetime(1970, 1, 1, tzinfo=pytz.UTC))
106
        context['start_date'] = min(omaha_start_date, mac_start_date).isoformat()
107
        platforms = list(get_platforms_by_appid(app))
108
        context['platforms'] = platforms
109
        context['platforms_list'] = json.dumps([p.name for p in platforms])
110
111
        return context
112
113
114
class LiveStatisticsView(StaffMemberRequiredMixin, DetailView):
115
    model = Application
116
    template_name = 'admin/omaha/live_statistics.html'
117
    context_object_name = 'app'
118
119
    def get_object(self, queryset=None):
120
        return get_object_or_404(Application, name=self.kwargs.get('name'))
121
122
    def get_context_data(self, **kwargs):
123
        context = super(LiveStatisticsView, self).get_context_data(**kwargs)
124
125
        app = self.object
126
127
        context['app_name'] = app.name
128
        platforms = list(get_platforms_by_appid(app))
129
        context['platforms'] = platforms
130
        context['platforms_list'] = json.dumps([p.name for p in platforms])
131
132
        return context
133
134
135
class VersionsUsageView(StaffMemberRequiredMixin, SingleTableView):
136
    model = AppRequest
137
    template_name = 'admin/omaha/version_usage.html'
138
    context_object_name = 'version_usage'
139
    table_class = VersionsUsageTable
140
141
    def get_queryset(self):
142
        qs = super(VersionsUsageView, self).get_queryset()
143
        self.appid = None
144
145
        try:
146
            app = Application.objects.get(name=self.kwargs.get('name'))
147
            qs = qs.filter(appid=app.id)
148
            self.appid = app.id
149
        except Application.DoesNotExist:
150
            raise Http404
151
152
        qs = qs.filter(events__eventtype__in=[2, 3], events__eventresult=1)
153
        qs = qs.distinct('request__userid').order_by('request__userid', '-request__created')
154
        qs = qs.only('id')
155
        sortable_qs = self.model.objects.filter(id__in=qs).select_related('request', 'request__os')
156
        return sortable_qs
157
158
    def get_context_data(self, **kwargs):
159
        context = super(VersionsUsageView, self).get_context_data(**kwargs)
160
        context['app_name'] = self.kwargs.get('name')
161
        return context
162
163
164
class RequestListView(StaffMemberRequiredMixin, SingleTableView):
165
    model = AppRequest
166
    context_object_name = 'request_list'
167
    template_name = 'admin/omaha/request_list.html'
168
    table_class = AppRequestTable
169
170
    def get_queryset(self):
171
        qs = super(RequestListView, self).get_queryset()
172
        qs = qs.select_related('request', 'request__os',)
173
        qs = qs.prefetch_related('events')
174
        qs = qs.order_by('-request__created')
175
        self.appid = None
176
177
        try:
178
            app = Application.objects.get(name=self.kwargs.get('name'))
179
            qs = qs.filter(appid=app.id)
180
            self.appid = app.id
181
        except Application.DoesNotExist:
182
            raise Http404
183
184
        qs = qs.distinct()
185
        self.filter = AppRequestFilter(self.request.GET, queryset=qs)
186
        return self.filter.qs
187
188
    def get_context_data(self, **kwargs):
189
        context = super(RequestListView, self).get_context_data(**kwargs)
190
        context['filter'] = self.filter
191
        context['app_name'] = self.kwargs.get('name')
192
        context['app_id'] = self.appid
193
        return context
194
195
196
class AppRequestDetailView(StaffMemberRequiredMixin, DetailView):
197
    model = AppRequest
198
    template_name = 'admin/omaha/request_detail.html'
199
200
    def get_queryset(self):
201
        qs = super(AppRequestDetailView, self).get_queryset()
202
        qs = qs.select_related('request', 'request__os', 'request__hw')
203
        qs = qs.prefetch_related('events')
204
        return qs
205
206
    def get_context_data(self, **kwargs):
207
        name = 'Unknown'
208
        try:
209
            app_req = self.get_object()
210
            app = Application.objects.get(id=app_req.appid)
211
            name = app.name
212
        except Application.DoesNotExist:
213
            logger.error('AppRequestDetailView DoesNotExist', exc_info=True, extra=dict(request=self.request))
214
        context = super(AppRequestDetailView, self).get_context_data(**kwargs)
215
        context['app_name'] = name
216
        context['EVENT_RESULT'] = EVENT_RESULT
217
        context['EVENT_TYPE'] = EVENT_TYPE
218
        context['STATE_CANCELLED'] = STATE_CANCELLED
219
        return context
220
221
222
class PreferenceFormView(StaffMemberRequiredMixin, FormView):
223
    template_name = 'admin/omaha/set_preferences.html'
224
    registry = global_preferences
225
226
    def get_success_url(self):
227
        return self.request.path
228
229
    def get_form_class(self, *args, **kwargs):
230
        section = self.kwargs.get('section', None)
231
        form_class = global_preference_form_builder(section=section)
232
        return form_class
233
234
    def get_context_data(self, *args, **kwargs):
235
        context = super(PreferenceFormView, self).get_context_data(*args, **kwargs)
236
        context['sections'] = self.registry.sections()
237
        context['sections'].sort()
238
        context['cur_section'] = self.kwargs.get('section')
239
        form = context['form']
240
        order_fields = ['Crash__limit_size', 'Crash__limit_storage_days', 'Crash__duplicate_number',
241
                        'Feedback__limit_size', 'Feedback__limit_storage_days', 'SparkleVersion__limit_size',
242
                        'Symbols__limit_size', 'Version__limit_size', 'Timezone__timezone']
243
        form.fields = OrderedDict((k, form.fields[k]) for k in order_fields if k in form.fields.keys())
244
        return context
245
246
    def form_valid(self, form):
247
        form.update_preferences()
248
        try:
249
            self.request.session['django_timezone'] = form.cleaned_data['Timezone__timezone']
250
        except KeyError:
251
            pass
252
        messages.add_message(self.request, messages.INFO, 'Preferences were updated')
253
        return super(PreferenceFormView, self).form_valid(form)
254
255
256
class MonitoringFormView(StaffMemberRequiredMixin, TemplateView):
257
    template_name = 'admin/omaha/monitoring.html'
258
    form_class = ManualCleanupForm
259
    success_url = reverse_lazy('monitoring')
260
261
    def get_context_data(self, **kwargs):
262
        context = super(MonitoringFormView, self).get_context_data(**kwargs)
263
        omaha_version_size = float(cache.get('omaha_version_size') or 0)/1073741824
264
        sparkle_version_size = float(cache.get('sparkle_version_size') or 0)/1073741824
265
        feedbacks_size = float(cache.get('feedbacks_size') or 0)/1073741824
266
        crashes_size = float(cache.get('crashes_size') or 0)/1073741824
267
        symbols_size = float(cache.get('symbols_size') or 0)/1073741824
268
269
        data = dict(
270
            omaha_version=dict(label='Omaha Versions', size=omaha_version_size, limit=gpm['Version__limit_size'], percent=omaha_version_size/gpm['Version__limit_size']*100),
271
            sparkle_version=dict(label='Sparkle Versions', size=sparkle_version_size, limit=gpm['SparkleVersion__limit_size'], percent=sparkle_version_size/gpm['SparkleVersion__limit_size']*100),
272
            feedbacks=dict(label='Feedbacks', size=feedbacks_size, limit=gpm['Feedback__limit_size'], percent=feedbacks_size/gpm['Feedback__limit_size']*100),
273
            crashes=dict(label='Crashes',  size=crashes_size, limit=gpm['Crash__limit_size'], percent=crashes_size/gpm['Crash__limit_size']*100),
274
            symbols=dict(label='Symbols',  size=symbols_size, limit=gpm['Symbols__limit_size'], percent=symbols_size/gpm['Symbols__limit_size']*100),
275
        )
276
        full_size = reduce(lambda res, x: res + x['size'], data.values(), 0)
277
        context.update(data)
278
        piechart = None
279
        if full_size:
280
            pie_data = [(x['label'], x['size']/full_size * 100) for x in data.values()]
281
            piechart = make_piechart('used_space', pie_data, unit="%")
282
        context.update({'used_space': piechart})
283
        return context
284
285
286
class ManualCleanupFormView(StaffMemberRequiredMixin, FormView):
287
    template_name = 'admin/omaha/manually_deletion.html'
288
    form_class = CrashManualCleanupForm
289
290
    def get_context_data(self, **kwargs):
291
        context = super(ManualCleanupFormView, self).get_context_data(**kwargs)
292
        context['tabs'] = (
293
            ('crash__Crash', 'Crash'),
294
            ('feedback__Feedback', 'Feedback'),
295
            ('omaha__Version', 'Omaha Version'),
296
            ('sparkle__SparkleVersion', 'Sparkle Version'),
297
            ('crash__Symbols', 'Symbols')
298
        )
299
        context['cur_tab'] = self.kwargs.get('model')
300
        return context
301
302
    def get_success_url(self):
303
        return reverse('monitoring')
304
305
    def get_initial(self):
306
        return {'type': self.kwargs.get('model')}
307
308
    def get_form_class(self):
309
        cur_tab = self.kwargs.get('model')
310
        if cur_tab == 'crash__Crash':
311
            return CrashManualCleanupForm
312
        if cur_tab in ('feedback__Feedback', 'omaha__Version', 'sparkle__SparkleVersion', 'crash__Symbols'):
313
            return ManualCleanupForm
314
        raise Http404
315
316
    def form_valid(self, form):
317
        form.cleanup()
318
        messages.add_message(self.request, messages.INFO, 'Task was added in queue. Execution can take a long time. Check results on Sentry after a while.')
319
        return super(ManualCleanupFormView, self).form_valid(form)
320