Skip to content

Commit 93001db

Browse files
committed
Add quota validator
1 parent cedcf10 commit 93001db

File tree

4 files changed

+172
-6
lines changed

4 files changed

+172
-6
lines changed

validatedfile/models.py

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,3 +32,31 @@ def clean(self, *args, **kwargs):
3232

3333
return data
3434

35+
36+
class FileQuota(object):
37+
def __init__(self, items = [], file_attr_name = None):
38+
self.items = items
39+
self.file_attr_name = file_attr_name
40+
41+
def current_usage(self):
42+
usage = 0
43+
for item in self.items:
44+
the_file = getattr(item, self.file_attr_name, None)
45+
if the_file:
46+
usage += the_file.size
47+
return usage
48+
49+
class QuotaValidator(object):
50+
def __init__(self, max_usage):
51+
self.quota = FileQuota()
52+
self.max_usage = max_usage
53+
54+
def set_quota(self, quota):
55+
self.quota = quota
56+
57+
def __call__(self, file):
58+
tried_usage = self.quota.current_usage() + file.size
59+
if tried_usage > self.max_usage:
60+
raise forms.ValidationError(_('Please keep the total uploaded files under %s. With this file, the total would be %s' %
61+
(filesizeformat(self.max_usage), filesizeformat(tried_usage))))
62+

validatedfile/tests/__init__.py

Lines changed: 105 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,10 @@
55

66
import os.path
77

8-
from models import TestModel, TestModelNoValidate
9-
from forms import TestModelForm, TestModelNoValidateForm
8+
from validatedfile.models import FileQuota
9+
10+
from models import TestModel, TestModelNoValidate, TestContainer, TestElement
11+
from forms import TestModelForm, TestModelNoValidateForm, TestElementForm
1012

1113
class ValidatedFileFieldTest(TestCase):
1214

@@ -15,14 +17,12 @@ class ValidatedFileFieldTest(TestCase):
1517

1618
def test_create_empty_instance(self):
1719
instance = TestModel.objects.create()
18-
instance.save()
1920

2021

2122
def test_create_instance_with_file(self):
2223
instance = TestModel.objects.create(
2324
the_file = File(self._get_sample_file('image2k.png'), 'the_file.png')
2425
)
25-
instance.save()
2626

2727
self._check_file_url(instance.the_file, 'the_file.png')
2828

@@ -120,6 +120,107 @@ def test_form_null_file(self):
120120
instance.delete()
121121

122122

123+
def test_quota_empty(self):
124+
container = TestContainer.objects.create(name = 'container1')
125+
126+
quota = FileQuota(container.test_elements.all(), 'the_file')
127+
self.assertEqual(quota.current_usage(), 0)
128+
129+
container.delete()
130+
131+
132+
def test_quota_one_file(self):
133+
container = TestContainer.objects.create(name = 'container1')
134+
element = TestElement.objects.create(
135+
container = container,
136+
the_file = File(self._get_sample_file('image2k.png'), 'the_file.png')
137+
)
138+
139+
quota = FileQuota(container.test_elements.all(), 'the_file')
140+
self.assertEqual(quota.current_usage(), 2120)
141+
142+
element.the_file.delete()
143+
element.delete()
144+
container.delete()
145+
146+
147+
def test_quota_several_files_several_containers(self):
148+
container1 = TestContainer.objects.create(name = 'container1')
149+
element1 = TestElement.objects.create(
150+
container = container1,
151+
the_file = File(self._get_sample_file('image2k.png'), 'the_file1.png')
152+
)
153+
element2 = TestElement.objects.create(
154+
container = container1,
155+
the_file = File(self._get_sample_file('image15k.png'), 'the_file2.png')
156+
)
157+
container2 = TestContainer.objects.create(name = 'container2')
158+
element3 = TestElement.objects.create(
159+
container = container2,
160+
the_file = File(self._get_sample_file('document15k.pdf'), 'the_file3.pdf')
161+
)
162+
163+
quota = FileQuota(container1.test_elements.all(), 'the_file')
164+
self.assertEqual(quota.current_usage(), 16706)
165+
166+
element1.the_file.delete()
167+
element2.the_file.delete()
168+
element3.the_file.delete()
169+
element1.delete()
170+
element2.delete()
171+
element3.delete()
172+
container1.delete()
173+
container2.delete()
174+
175+
176+
def test_form_quota_ok(self):
177+
container = TestContainer.objects.create(name = 'container1')
178+
179+
quota = FileQuota(container.test_elements.all(), 'the_file')
180+
uploaded_file = SimpleUploadedFile(
181+
name = 'the_file.png',
182+
content = self._get_sample_file('image2k.png').read(),
183+
content_type = 'image/png',
184+
)
185+
form = TestElementForm(
186+
container = container,
187+
quota = quota,
188+
data = {},
189+
files = {'the_file': uploaded_file}
190+
)
191+
192+
self.assertTrue(form.is_valid())
193+
194+
container.delete()
195+
196+
197+
def test_form_quota_exceeded(self):
198+
container = TestContainer.objects.create(name = 'container1')
199+
element = TestElement.objects.create(
200+
container = container,
201+
the_file = File(self._get_sample_file('image2k.png'), 'the_file.png')
202+
)
203+
204+
quota = FileQuota(container.test_elements.all(), 'the_file')
205+
uploaded_file = SimpleUploadedFile(
206+
name = 'the_file.png',
207+
content = self._get_sample_file('image15k.png').read(),
208+
content_type = 'image/png',
209+
)
210+
form = TestElementForm(
211+
container = container,
212+
quota = quota,
213+
data = {},
214+
files = {'the_file': uploaded_file}
215+
)
216+
217+
self.assertFalse(form.is_valid())
218+
219+
element.the_file.delete()
220+
element.delete()
221+
container.delete()
222+
223+
123224
# Utilities
124225

125226
def _get_sample_file(self, filename):

validatedfile/tests/forms.py

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,35 @@
11
from django import forms
2-
from models import TestModel, TestModelNoValidate
2+
from models import TestModel, TestModelNoValidate, TestContainer, TestElement
3+
from validatedfile.models import QuotaValidator
34

45
class TestModelForm(forms.ModelForm):
56

67
class Meta:
78
model = TestModel
89

10+
911
class TestModelNoValidateForm(forms.ModelForm):
1012

1113
class Meta:
1214
model = TestModelNoValidate
1315

16+
17+
class TestElementForm(forms.ModelForm):
18+
19+
the_file = forms.FileField(required = False,
20+
validators = [QuotaValidator(max_usage = 10000)])
21+
22+
class Meta:
23+
model = TestElement
24+
fields = ['the_file']
25+
26+
def __init__(self, container, quota, *args, **kwargs):
27+
super(TestElementForm, self).__init__(*args, **kwargs)
28+
self.container = container
29+
self.fields['the_file'].validators[0].set_quota(quota)
30+
31+
def save(self, *args, **kwargs):
32+
element = super(TestElementForm, self).save(commit = False)
33+
element.container = self.container
34+
element.save()
35+

validatedfile/tests/models.py

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
from django.db import models
2-
from validatedfile.models import ValidatedFileField
2+
from validatedfile.models import ValidatedFileField, QuotaValidator
33

44
class TestModel(models.Model):
55
the_file = ValidatedFileField(
@@ -15,3 +15,18 @@ class TestModelNoValidate(models.Model):
1515
blank = True,
1616
upload_to = 'testfile')
1717

18+
19+
class TestContainer(models.Model):
20+
name = models.CharField(max_length = 100)
21+
22+
23+
class TestElement(models.Model):
24+
container = models.ForeignKey(
25+
TestContainer,
26+
related_name = 'test_elements')
27+
the_file = ValidatedFileField(
28+
null = True,
29+
blank = True,
30+
upload_to = 'testfile',
31+
content_types = ['image/png', 'image/jpeg'])
32+

0 commit comments

Comments
 (0)