Completed
Push — master ( 319370...171ce4 )
by
unknown
01:23
created

pre_crash_save()   A

Complexity

Conditions 4

Size

Total Lines 12

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 4
c 0
b 0
f 0
dl 0
loc 12
rs 9.2
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 os
22
import uuid
23
24
from django.db import models
25
from django.db.models.signals import post_save, pre_delete, pre_save
26
from django.dispatch import receiver
27
from django.utils import timezone
28
29
from celery import signature
30
from jsonfield import JSONField
31
32
from omaha.models import BaseModel
33
from crash.managers import CrashManager, SymbolsManager
34
35
36 View Code Duplication
def upload_to(directory, obj, filename):
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
37
    now = timezone.now()
38
    max_length = 255
39
    path = os.path.join(*map(str, [directory, now.year, now.month,
40
                                   now.day, uuid.uuid4(), filename]))
41
    if len(path) > max_length:
42
        name, ext = os.path.splitext(path)
43
        ext_length = len(ext)
44
        path = name[:max_length-ext_length] + ext
45
    return path
46
47
48
def crash_upload_to(obj, filename):
49
    return upload_to('minidump', obj, filename)
50
51
52
def crash_archive_upload_to(obj, filename):
53
    return upload_to('minidump_archive', obj, filename)
54
55
56
class Crash(BaseModel):
57
    upload_file_minidump = models.FileField(upload_to=crash_upload_to, blank=True, null=True, max_length=255)
58
    minidump_size = models.PositiveIntegerField(null=True, blank=True)
59
    archive = models.FileField(upload_to=crash_archive_upload_to, blank=True, null=True, max_length=255)
60
    archive_size = models.PositiveIntegerField(null=True, blank=True)
61
    appid = models.CharField(max_length=38, null=True, blank=True)
62
    userid = models.CharField(max_length=38, null=True, blank=True)
63
    meta = JSONField(verbose_name='Meta-information', help_text='JSON format', null=True, blank=True)
64
    stacktrace = models.TextField(null=True, blank=True)
65
    stacktrace_json = JSONField(null=True, blank=True)
66
    signature = models.CharField(max_length=255, db_index=True, null=True, blank=True)
67
    ip = models.GenericIPAddressField(blank=True, null=True, protocol="ipv4")
68
    groupid = models.CharField(max_length=38, null=True, blank=True)
69
    eventid = models.CharField(max_length=38, null=True, blank=True)
70
71
    objects = CrashManager()
72
73
    class Meta(BaseModel.Meta):
74
        verbose_name_plural = 'Crashes'
75
76
    def __unicode__(self):
77
        return u"Crash #{0}".format(self.id) + (" ({0})".format(self.signature) if self.signature else '')
78
79
    @property
80
    def size(self):
81
        return self.archive_size + self.minidump_size
82
83
84
class CrashDescription(BaseModel):
85
    crash = models.OneToOneField(Crash, related_name='crash_description')
86
    summary = models.CharField(max_length=500)
87
    description = models.TextField(null=True, blank=True)
88
89
90
def symbols_upload_to(obj, filename):
91
    sym_filename = os.path.splitext(os.path.basename(obj.debug_file))[0]
92
    sym_filename = '%s.sym' % sym_filename
93
    return os.path.join('symbols', obj.debug_file, obj.debug_id, sym_filename)
94
95
96
class Symbols(BaseModel):
97
    debug_id = models.CharField(verbose_name='Debug ID', max_length=255, db_index=True, null=True, blank=True)
98
    debug_file = models.CharField(verbose_name='Debug file name', max_length=140, null=True, blank=True)
99
    file = models.FileField(upload_to=symbols_upload_to, null=True)
100
    file_size = models.PositiveIntegerField(null=True, blank=True)
101
102
    objects = SymbolsManager()
103
104
    class Meta:
105
        verbose_name_plural = 'Symbols'
106
        unique_together = (
107
            ('debug_id', 'debug_file'),
108
        )
109
110
    @property
111
    def size(self):
112
         return self.file_size
113
114
115
@receiver(pre_save, sender=Crash)
116
def pre_crash_save(sender, instance, *args, **kwargs):
117
    if instance.pk:
118
        old = sender.objects.get(pk=instance.pk)
119
        if old.upload_file_minidump != instance.upload_file_minidump:
120
            old.upload_file_minidump.delete(save=False)
121
            old.minidump_size = 0
122
            old.archive.delete(save=False)
123
            old.archive_size = 0
124
        elif old.archive != instance.archive:
125
            old.archive.delete(save=False)
126
            old.archive_size = 0
127
128
129
@receiver(post_save, sender=Crash)
130
def crash_post_save(sender, instance, created, *args, **kwargs):
131
    if created and instance.upload_file_minidump:
132
        signature("tasks.processing_crash_dump", args=(instance.pk,)).apply_async(queue='private', countdown=1)
133
134
135
@receiver(pre_delete, sender=Crash)
136
def pre_crash_delete(sender, instance, **kwargs):
137
    file_fields = [instance.archive, instance.upload_file_minidump]
138
    for field in file_fields:
139
        storage, name = field.storage, field.name
140
        if name:
141
            storage.delete(name)
142
143
144
@receiver(pre_save, sender=Symbols)
145
def pre_symbol_save(sender, instance, *args, **kwargs):
146
    if instance.pk:
147
        old = sender.objects.get(pk=instance.pk)
148
        if old.file == instance.file:
149
            return
150
        else:
151
            old.file.delete(save=False)
152
            old.file_size = 0
153
154
155
@receiver(pre_delete, sender=Symbols)
156
def pre_symbol_delete(sender, instance, **kwargs):
157
    storage, name = instance.file.storage, instance.file.name
158
    if name:
159
        storage.delete(name)
160