Completed
Pull Request — master (#207)
by Kirill
01:34
created

CrashFrom

Size/Duplication

Total Lines 49
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
dl 0
loc 49
c 0
b 0
f 0

4 Methods

Rating   Name   Duplication   Size   Complexity  
A clean_archive() 0 2 1
A clean_minidump_size() 0 7 3
A clean_archive_size() 0 7 3
B clean_upload_file_minidump() 0 18 6
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 filter
22
23
import tarfile
24
from io import BytesIO
25
26
from django import forms
27
from django.core.files.uploadedfile import SimpleUploadedFile
28
from django.forms import widgets
29
from django.forms.widgets import TextInput
30
from django.core.files.uploadedfile import UploadedFile
31
32
from django_ace import AceWidget
33
from crash.models import Symbols, Crash, CrashDescription
34
from crash.utils import parse_debug_meta_info
35
36
37
class CrashFrom(forms.ModelForm):
38
    class Meta:
39
        model = Crash
40
        exclude = []
41
        widgets = {
42
            'stacktrace_json': AceWidget(mode='json', theme='monokai', width='600px', height='300px'),
43
            'stacktrace': AceWidget(theme='monokai', width='600px', height='300px'),
44
            'meta': AceWidget(mode='json', theme='monokai', width='600px', height='300px'),
45
            'archive_size': widgets.TextInput(attrs=dict(disabled='disabled')),
46
            'minidump_size': widgets.TextInput(attrs=dict(disabled='disabled')),
47
        }
48
49
    def clean_archive(self):
50
        return self.cleaned_data.get('archive_file')
51
52
    def clean_upload_file_minidump(self):
53
        file = self.cleaned_data["upload_file_minidump"]
54
55
        if file and file.name.endswith('.tar'):
56
            try:
57
                t_file = BytesIO(file.read())
58
                t_file = tarfile.open(fileobj=t_file, mode='r')
59
                self.cleaned_data['archive_file'] = file
60
                dump_name = filter(lambda i: i.endswith('.dmp'), t_file.getnames())
61
                try:
62
                    file_name = next(dump_name)
63
                    file = t_file.extractfile(file_name)
64
                    file = SimpleUploadedFile(file_name, file.read())
65
                except StopIteration:
66
                    return None
67
            except tarfile.TarError as err:
68
                raise forms.ValidationError('The tar file is broken, error: {0}'.format(err.message))
69
        return file
70
71
    def clean_minidump_size(self):
72
        if 'upload_file_minidump' not in self.cleaned_data:
73
            raise forms.ValidationError('')
74
        _file = self.cleaned_data.get('upload_file_minidump')
75
        if isinstance(_file, UploadedFile):
76
            return _file.size
77
        return self.initial.get("minidump_size")
78
79
    def clean_archive_size(self):
80
        if 'archive_file' not in self.cleaned_data:
81
            return 0
82
        _file = self.cleaned_data.get('archive_file', 0)
83
        if isinstance(_file, UploadedFile):
84
            return _file.size
85
        return self.initial.get("archive_size", 0)
86
87
88
class CrashDescriptionForm(forms.ModelForm):
89
    class Meta:
90
        model = CrashDescription
91
        fields = ['summary', 'description']
92
93
94
class SymbolsFileInput(forms.ClearableFileInput):
95
    url_markup_template = '<a href="{0}">Link</a>'
96
97
98
class SymbolsFileField(forms.Field):
99
    widget = SymbolsFileInput
100
101
102
class SymbolsAdminForm(forms.ModelForm):
103
    file = SymbolsFileField()
104
105
    class Meta:
106
        model = Symbols
107
        exclude = []
108
        widgets = {
109
            'debug_id': widgets.TextInput(attrs=dict(disabled='disabled')),
110
            'debug_file': widgets.TextInput(attrs=dict(disabled='disabled')),
111
            'file_size': widgets.TextInput(attrs=dict(disabled='disabled')),
112
        }
113
114
    def clean_file(self):
115
        file = self.cleaned_data["file"]
116
        try:
117
            head = file.readline().rstrip()
118
            meta = parse_debug_meta_info(head, exception=forms.ValidationError)
119
            self.cleaned_data.update(meta)
120
        except:
121
            raise forms.ValidationError(u"The file contains invalid data.")
122
        return file
123
124
    def clean_file_size(self):
125
        if 'file' not in self.cleaned_data:
126
            raise forms.ValidationError('')
127
        _file = self.cleaned_data["file"]
128
        if isinstance(_file, UploadedFile):
129
            return _file.size
130
        return self.initial["file_size"]
131
132
class TextInputForm(forms.Form):
133
    def __init__(self, *args, **kwargs):
134
        field_name = kwargs.pop('field_name')
135
        super(TextInputForm, self).__init__(*args, **kwargs)
136
        self.fields[field_name] = forms.CharField(
137
            widget=TextInput(attrs={'placeholder': 'Filter by ID'}),
138
            label='',
139
            required=False)
140
141
    def is_valid(self):
142
        valid = super(TextInputForm, self).is_valid()
143
        if not valid:
144
            return valid
145
        _id = self.cleaned_data['id']
146
        if _id and not _id.isdigit():
147
            self.add_error('id', 'ID should be integer')
148
            return False
149
        return True
150