aboutsummaryrefslogtreecommitdiffstats
path: root/account/extra.py
blob: d0f74f2e5dab434cf5261e726acbc0c7ec9eda6d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
# -*- coding: utf-8 -*-

"""
Extra models for app account
"""

from django import forms
from django.db import models
from django.db.models.fields.files import FieldFile
from django.core.files.storage import FileSystemStorage
from django.conf import settings
from django.template.defaultfilters import filesizeformat
from django.utils.translation import ugettext_lazy as _

from south.modelsinspector import add_introspection_rules

import os


### custom fields ###
class ContentTypeRestrictedFileField(models.FileField):
    """
    Same as FileField, but you can specify:
        * content_types - list containing allowed content_types.
            Example: ['application/pdf', 'image/jpeg']
        * max_upload_size - a number indicating the maximum file
            size allowed for upload.
            2.5MB - 2621440
            5MB   - 5242880
            10MB  - 10485760
            20MB  - 20971520
            50MB  - 52428800
            100MB - 104857600
            250MB - 214958080
            500MB - 429916160
    """
    def __init__(self, *args, **kwargs):
        self.content_types = kwargs.pop("content_types")
        self.max_upload_size = kwargs.pop("max_upload_size")
        super(ContentTypeRestrictedFileField, self).__init__(*args, **kwargs)

    def clean(self, *args, **kwargs):
        data = super(ContentTypeRestrictedFileField, self).clean(*args, **kwargs)
        file = data.file
        # check content type and file size
        try:
            content_type = file.content_type
            #print content_type
            #raise forms.ValidationError(_("Invalid filetype."), code='invalid')
            if content_type in self.content_types:
                if file._size > self.max_upload_size:
                    raise forms.ValidationError(_('Please keep filesize under %(maxsize)s. Current filesize %(filesize)s') % {'maxsize':filesizeformat(self.max_upload_size), 'filesize':filesizeformat(file._size)}, code='invalid')
            else:
                raise forms.ValidationError(_("Unsupported filetype"), code='invalid')
        except AttributeError:
            pass
        #
        return data

## add custom fields to south inspection
add_introspection_rules([
    (
        [ContentTypeRestrictedFileField],   # class these apply to
        [],                                 # positional arguments
        {                                   # keyword argument
            "content_types": ["content_types", {}],
            "max_upload_size": ["max_upload_size", {}],
        },
    ),
], ["^account\.extra\.ContentTypeRestrictedFileField"])


### OverwriteStorage ###
class OverwriteStorage(FileSystemStorage):
    """
    overwrite original file before store the new one
    """
    def get_available_name(self, name):
        """
        Returns a filename that's free on the target storage system,
        and available for new content to be written to.
        Ref: http://djangosnippets.org/snippets/976/

        This file storage solves overwrite on upload problem. Another
        proposed solution was to override the save method on the model
        like so (from https://code.djangoproject.com/ticket/11663):

        def save(self, *args, **kwargs):
            try:
                this = MyModelName.objects.get(id=self.id)
                if this.MyImageFieldName != self.MyImageFieldName:
                    this.MyImageFieldName.delete()
            except: pass
            super(MyModelName, self).save(*args, **kwargs)
        """
        # If the filename already exists,
        # remove it as if it was a true file system
        if self.exists(name):
            filepath = os.path.join(settings.MEDIA_ROOT, name)
            if os.path.isfile(filepath):
                os.remove(filepath)
        return name


### delete files associated with model FileField
# Pre-delete signal function for deleting files a model
# https://djangosnippets.org/snippets/2820/
def file_cleanup(sender, instance, *args, **kwargs):
    """
    Deletes the file(s) associated with a model instance. The model
    is not saved after deletion of the file(s) since this is meant
    to be used with the pre_delete signal.
    """
    for field_name, _ in instance.__dict__.iteritems():
        field = getattr(instance, field_name)
        if (issubclass(field.__class__, FieldFile) and field.name):
            # pass False so FileField does not save the model
            field.delete(save=False)