Completed
Push — master ( 97e35d...b2374c )
by
unknown
45s
created

CrashAdmin   A

Complexity

Total Complexity 16

Size/Duplication

Total Lines 57
Duplicated Lines 0 %

Importance

Changes 1
Bugs 1 Features 0
Metric Value
dl 0
loc 57
rs 10
c 1
b 1
f 0
wmc 16

6 Methods

Rating   Name   Duplication   Size   Complexity  
A archive_field() 0 2 1
A regenerate_stacktrace() 0 3 2
A cpu_architecture_field() 0 2 2
A summary_field() 0 5 2
B sentry_link_field() 0 13 6
A get_form() 0 7 3
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 django.contrib import admin
22
from django.core.exceptions import ObjectDoesNotExist
23
from django.conf import settings
24
from django.utils.html import format_html
25
26
from celery import signature
27
28
from crash.forms import SymbolsAdminForm, CrashFrom
29
from crash.models import Crash, CrashDescription, Symbols
30
from crash.forms import TextInputForm
31
32
SENTRY_DOMAIN = getattr(settings, 'SENTRY_STACKTRACE_DOMAIN', None)
33
SENTRY_ORG_SLUG = getattr(settings, 'SENTRY_STACKTRACE_ORG_SLUG', None)
34
SENTRY_PROJ_SLUG = getattr(settings, 'SENTRY_STACKTRACE_PROJ_SLUG', None)
35
CRASH_TRACKER = getattr(settings, 'CRASH_TRACKER', None)
36
37
class BooleanFilter(admin.SimpleListFilter):
38
    title = None
39
    parameter_name = None
40
41
    def lookups(self, request, model_admin):
42
        return (
43
            ('yes', 'Yes'),
44
            ('no', 'No'),
45
        )
46
47
    def queryset(self, request, queryset):
48
        d = {self.parameter_name: ''}
49
        if self.value() == 'yes':
50
            return queryset.exclude(**d)
51
        if self.value() == 'no':
52
            return queryset.filter(**d)
53
54
55
class TextInputFilter(admin.filters.FieldListFilter):
56
    template = 'admin/textinput_filter.html'
57
58
    def __init__(self, field, request, params, model, model_admin, field_path):
59
        self.lookup_kwarg_equal = '%s' % field_path
60
        super(TextInputFilter, self).__init__(
61
            field, request, params, model, model_admin, field_path)
62
        self.form = self.get_form()
63
64
    def choices(self, cl):
65
        return []
66
67
    def expected_parameters(self):
68
        return [self.lookup_kwarg_equal]
69
70
    def get_form(self):
71
        return TextInputForm(data=self.used_parameters,
72
                             field_name=self.field_path)
73
74
    def queryset(self, request, queryset):
75
        if self.form.is_valid():
76
            filter_params = dict(filter(lambda x: bool(x[1]),
77
                                        self.form.cleaned_data.items()))
78
            return queryset.filter(**filter_params)
79
        else:
80
            return queryset
81
82
83
class CrashArchiveFilter(BooleanFilter):
84
    title = 'Instrumental file'
85
    parameter_name = 'archive'
86
87
88
@admin.register(CrashDescription)
89
class CrashDescriptionAdmin(admin.ModelAdmin):
90
    readonly_fields = ('created', 'modified')
91
    list_display = ('created', 'modified', 'summary')
92
    list_display_links = ('created', 'modified', 'summary')
93
94
95
class CrashDescriptionInline(admin.StackedInline):
96
    model = CrashDescription
97
98
99
@admin.register(Crash)
100
class CrashAdmin(admin.ModelAdmin):
101
    list_display = ('id', 'created', 'modified', 'archive_field', 'signature', 'appid', 'userid', 'summary_field', 'os', 'build_number', 'channel', 'cpu_architecture_field',)
102
    list_select_related = ['crash_description']
103
    list_display_links = ('id', 'created', 'modified', 'signature', 'appid', 'userid', 'cpu_architecture_field',)
104
    list_filter = (('id', TextInputFilter,), 'created', CrashArchiveFilter, 'os', 'build_number', 'channel')
105
    search_fields = ('appid', 'userid', 'archive',)
106
    form = CrashFrom
107
    readonly_fields = ['sentry_link_field', 'os', 'build_number', 'channel',]
108
    exclude = ('groupid', 'eventid', )
109
    actions = ('regenerate_stacktrace',)
110
    inlines = [CrashDescriptionInline]
111
112
    def archive_field(self, obj):
113
        return bool(obj.archive)
114
    archive_field.short_description = 'Instrumental file'
115
116
    def cpu_architecture_field(self, obj):
117
        return obj.stacktrace_json.get('system_info', {}).get('cpu_arch', '') if obj.stacktrace_json else ''
118
    cpu_architecture_field.short_description = "CPU Architecture"
119
120
    def sentry_link_field(self, obj):
121
        if not SENTRY_DOMAIN or not SENTRY_ORG_SLUG or not SENTRY_PROJ_SLUG:
122
            return "Sentry variables are not set"
123
        if not obj.groupid or not obj.eventid:
124
            return "No sentry link"
125
        link = "http://{}/{}/{}/group/{}/events/{}/".format(
126
            SENTRY_DOMAIN,
127
            SENTRY_ORG_SLUG,
128
            SENTRY_PROJ_SLUG,
129
            obj.groupid,
130
            obj.eventid
131
        )
132
        return format_html("<a href='{link}'>{link}</a>".format(link=link))
133
134
    sentry_link_field.short_description = "Sentry link"
135
    sentry_link_field.allow_tags = True
136
137
    def summary_field(self, obj):
138
        try:
139
            return obj.crash_description.summary
140
        except ObjectDoesNotExist:
141
            return None
142
    summary_field.short_description = 'Summary'
143
144
    def regenerate_stacktrace(self, request, queryset):
145
        for i in queryset:
146
            signature("tasks.processing_crash_dump", args=(i.pk,)).apply_async(queue='default')
147
    regenerate_stacktrace.short_description = 'Regenerate stacktrace'
148
149
    def get_form(self, request, obj=None, **kwargs):
150
        if CRASH_TRACKER != 'Sentry':
151
            try:
152
                self.readonly_fields.remove('sentry_link_field')
153
            except ValueError:
154
                pass
155
        return super(CrashAdmin, self).get_form(request, obj, **kwargs)
156
157
158
@admin.register(Symbols)
159
class SymbolsAdmin(admin.ModelAdmin):
160
    readonly_fields = ('created', 'modified', )
161
    list_display = ('created', 'modified', 'debug_file', 'debug_id',)
162
    list_display_links = ('created', 'modified', 'debug_file', 'debug_id',)
163
    form = SymbolsAdminForm
164
165