diff options
author | Rogelio Mita <rogeliomita@activitycentral.com> | 2013-07-31 00:45:17 (GMT) |
---|---|---|
committer | Rogelio Mita <rogeliomita@activitycentral.com> | 2013-07-31 02:18:06 (GMT) |
commit | 4cf5c2b581d12dd8c23efcf7c7b667e9e4efde80 (patch) | |
tree | 82a38aea5c67c165acbfb140d35523168cd8a655 | |
parent | 9b17f03e8ab9e40e95b87f595b8c81bea1272fcb (diff) |
Save image for a field
-rw-r--r-- | .gitignore | 2 | ||||
-rw-r--r-- | webapp/coffee/factoryField.coffee | 3 | ||||
-rw-r--r-- | webapp/js_tests/fixtures/container.html | 1 | ||||
-rw-r--r-- | webapp/polls/models.py | 85 | ||||
-rw-r--r-- | webapp/polls/templates/mustache/field.html | 4 | ||||
-rw-r--r-- | webapp/polls/templates/tags/structure.html | 2 | ||||
-rw-r--r-- | webapp/polls/templatetags/poll_tags.py | 4 | ||||
-rw-r--r-- | webapp/polls/tests/field_tests.py | 25 | ||||
-rw-r--r-- | webapp/polls/tests/structure_tests.py | 10 | ||||
-rw-r--r-- | webapp/polls/views.py | 2 | ||||
-rw-r--r-- | webapp/webapp/media/images/empty | 0 | ||||
-rw-r--r-- | webapp/webapp/settings.py | 4 | ||||
-rw-r--r-- | webapp/webapp/static/js/factoryField.js | 3 |
13 files changed, 133 insertions, 12 deletions
@@ -5,6 +5,8 @@ webapp/webapp/media/cache/ webapp/webapp/media/image_options/* !webapp/webapp/media/image_options/empty +webapp/webapp/media/images/* +!webapp/webapp/media/images/empty webapp/webapp/env_settings.py database.db webapp/webapp/media/results_bck/* diff --git a/webapp/coffee/factoryField.coffee b/webapp/coffee/factoryField.coffee index b24d07c..ccba883 100644 --- a/webapp/coffee/factoryField.coffee +++ b/webapp/coffee/factoryField.coffee @@ -49,7 +49,8 @@ factoryField = (order, value) -> "visible_errors": errors.length, "WIDGET_TYPES": widget_types, "dependence_forms": dependence_forms, - "img_src": value['img_src'] + "img_src": IMAGE_MEDIA_URL + "/" + value['img'], + "img_name": value['img'], } ) ) diff --git a/webapp/js_tests/fixtures/container.html b/webapp/js_tests/fixtures/container.html index d1b1cc1..64e27d3 100644 --- a/webapp/js_tests/fixtures/container.html +++ b/webapp/js_tests/fixtures/container.html @@ -24,5 +24,6 @@ OFFSET_OPTION_ID = 0, WITH_IMAGES = ["ImageCheckBox", "ImageRadioButton"], IMAGE_OPTIONS_TMP_MEDIA_URL, + IMAGE_MEDIA_URL, POLL_ID; </script>
\ No newline at end of file diff --git a/webapp/polls/models.py b/webapp/polls/models.py index 7c657cb..f4d9ed1 100644 --- a/webapp/polls/models.py +++ b/webapp/polls/models.py @@ -669,6 +669,7 @@ class Field(AbstractObject, ComponentStructure): self.order = int(order) if order else order self.name = data.get('name', None) self.img = data.get('img', None) + self.uploaded_file = data.get("uploaded_file", None) value = data.get('dependence', None) self.dependence = value @@ -735,6 +736,13 @@ class Field(AbstractObject, ComponentStructure): if img and opt not in self.options: self.options.append(opt) + def img_validate(self, img_file): + try: + ImageField().to_python(img_file) + except DjangoValidationError, e: + self.img = None + raise Field.ValidationError(e.messages[0]) + def validate(self, options=[], new_data=None): self.errors = [] rule, msg = Field.VALIDATION_RULES.get(self.widget_type) @@ -797,9 +805,32 @@ class Field(AbstractObject, ComponentStructure): msg = "Necesita ingresar una pregunta" self.errors.append(msg) + if self.uploaded_file: + try: + self.img_validate(self.uploaded_file) + except Field.ValidationError: + self.errors.append(u"Pregunta con imagen no válida.") + if len(self.errors): raise Field.ValidationError(str(self.errors)) + def storing_image(self, path, img_file): + img_path = path + '/%s' % img_file.name + if os.path.exists(img_path): + os.remove(img_path) + + with open(img_path, 'wb+') as dst: + for chunk in img_file.chunks(): + dst.write(chunk) + dst.close() + + def store_image(self, path): + if self.uploaded_file: + self.storing_image(path, self.uploaded_file) + + def get_img_name(self): + return getattr(self.uploaded_file, "name", self.img) + def to_python(self, with_errors=False, img_serialize=False): data = {} @@ -811,6 +842,10 @@ class Field(AbstractObject, ComponentStructure): if self.dependence: data.update({'dependence': self.dependence}) + img_name = self.get_img_name() + if img_name: + data.update({"img": img_name}) + if with_errors: data.update({'errors': self.errors}) @@ -969,10 +1004,22 @@ class Structure(AbstractObject, ComponentStructure): return options + def get_image_media_url(self): + return settings.IMAGES_MEDIA_URL + '/%s' % self.poll_id + def get_image_options(self): options = self.get_options() return filter(lambda opt: opt.img_name is not None, options) + def get_images_fields(self): + fields = [] + for group in self.groups: + for field in group.fields: + fields.append(field) + + fields = filter(lambda opt: field.get_img_name() is not None, fields) + return [field.get_img_name() for field in fields] + def validate(self): self.errors = [] @@ -1042,8 +1089,6 @@ class Structure(AbstractObject, ComponentStructure): if self.id: _dict.update({'_id': ObjectId(self.id)}) - print _dict - # Save process -> Update if it has an id, else insert structure_id = get_db().structures.save(_dict) @@ -1058,6 +1103,16 @@ class Structure(AbstractObject, ComponentStructure): except: pass + # Removing older img files + current_img_fields = self.get_images_fields() + path = self.get_image_path() + for file in os.listdir(path): + if file not in current_img_fields: + try: + os.remove("%s/%s" % (path, file)) + except: + pass + return structure_id @staticmethod @@ -1118,6 +1173,32 @@ class Structure(AbstractObject, ComponentStructure): dst.write(chunk) dst.close() + def get_image_tmp_path(self): + path = settings.IMAGES_ROOT + '/%s/tmp' % self.poll_id + + try: + os.makedirs(path) + except OSError: + pass + + return path + + def get_image_path(self): + path = settings.IMAGES_ROOT + '/%s' % self.poll_id + + try: + os.makedirs(path) + except OSError: + pass + + return path + + def save_image_fields(self): + + for group in self.groups: + for field in group.fields: + field.store_image(path=self.get_image_path()) + def save_image_options(self, tmp=False): options = self.get_options() diff --git a/webapp/polls/templates/mustache/field.html b/webapp/polls/templates/mustache/field.html index a967893..07a5766 100644 --- a/webapp/polls/templates/mustache/field.html +++ b/webapp/polls/templates/mustache/field.html @@ -49,6 +49,8 @@ value="[[ name ]]" placeholder="Pregunta..." /> + <input type="hidden" name="groups.[[ group_order ]].fields.[[ order ]].img" value="[[ img_name ]]" /> + <div class="fileupload fileupload-new" data-provides="fileupload"> <div class="fileupload-new thumbnail" style="width: 50px; height: 50px;"> <img src="[[ img_src ]]" /></div> @@ -56,7 +58,7 @@ <span class="btn btn-file"> <span class="fileupload-new">Elegir imagen</span> <span class="fileupload-exists">Change</span> - <input type="file" name="groups.[[ group_order ]].fields.[[ order ]].img"/> + <input type="file" name="groups.[[ group_order ]].fields.[[ order ]].uploaded_file" /> </span> <a href="#" class="btn fileupload-exists" data-dismiss="fileupload">Remove</a> </div> diff --git a/webapp/polls/templates/tags/structure.html b/webapp/polls/templates/tags/structure.html index efe46d9..61e0c63 100644 --- a/webapp/polls/templates/tags/structure.html +++ b/webapp/polls/templates/tags/structure.html @@ -43,8 +43,8 @@ WITH_IMAGES = {{ WITH_IMAGES|json }}, OFFSET_OPTION_ID = {{ OFFSET_OPTION_ID|json }}, IMAGE_OPTIONS_TMP_MEDIA_URL = {{ IMAGE_OPTIONS_TMP_MEDIA_URL|json }}, + IMAGE_MEDIA_URL = {{ IMAGE_MEDIA_URL|json }}, POLL_ID = {{ POLL_ID|json }}; - </script> diff --git a/webapp/polls/templatetags/poll_tags.py b/webapp/polls/templatetags/poll_tags.py index c28d237..5cbb284 100644 --- a/webapp/polls/templatetags/poll_tags.py +++ b/webapp/polls/templatetags/poll_tags.py @@ -11,6 +11,7 @@ register = template.Library() def render_structure(context, structure): structure_data = structure.to_python(with_errors=True) IMAGE_OPTIONS_TMP_MEDIA_URL = structure.get_image_options_tmp_media_url() + IMAGE_MEDIA_URL = structure.get_image_media_url() return render_to_string( 'tags/structure.html', @@ -22,7 +23,8 @@ def render_structure(context, structure): "OFFSET_OPTION_ID": Field.get_offset_id(), "IMAGE_OPTIONS_TMP_MEDIA_URL": IMAGE_OPTIONS_TMP_MEDIA_URL, "POLL_ID": str(context['poll'].id), - "groups": structure_data.get("groups", {}) + "groups": structure_data.get("groups", {}), + "IMAGE_MEDIA_URL": IMAGE_MEDIA_URL } ) diff --git a/webapp/polls/tests/field_tests.py b/webapp/polls/tests/field_tests.py index b7c6a18..8609357 100644 --- a/webapp/polls/tests/field_tests.py +++ b/webapp/polls/tests/field_tests.py @@ -4,7 +4,7 @@ from django.test import TestCase from polls.models import ( Poll, Dependence, Field, WIDGET_TYPES, WITH_OPTIONS, WITH_IMAGES) -from utils.test import MongoTestCase, mock_in_memory_image +from utils.test import MongoTestCase, mock_in_memory_image, mock_text_file class DependenceTests(TestCase): @@ -240,6 +240,19 @@ class FieldTests(MongoTestCase): self.assertRaises(Field.ValidationError, self.field.validate) self.assertEqual(1, len(self.field.errors)) + def test_to_python_with_img_name(self): + + data = { + 'order': 0, + 'name': "field_0", + } + field = Field(data=data) + field.img = 'img_name' + + to_python = field.to_python()['0'] + self.assertTrue('img' in to_python.keys()) + self.assertEqual('img_name', to_python['img']) + def test_to_python(self): # Widget_type = TextInput @@ -384,3 +397,13 @@ class FieldTests(MongoTestCase): 'values': ['ID', 'AND', 'ID'] } self.assertEqual(expected, field.dependence) + + def test_image_validation(self): + invalid_img_file = mock_text_file() + + data = {'id': '0', 'name': 'name', 'img': invalid_img_file} + field = Field(data) + + img_validate = lambda: field.img_validate(invalid_img_file) + self.assertRaises(Field.ValidationError, img_validate) + self.assertIsNone(field.img) diff --git a/webapp/polls/tests/structure_tests.py b/webapp/polls/tests/structure_tests.py index c4081fb..cd10d56 100644 --- a/webapp/polls/tests/structure_tests.py +++ b/webapp/polls/tests/structure_tests.py @@ -1,7 +1,7 @@ # -*- encoding: utf-8 -*- from polls.models import Poll, Group, Field, Structure -from utils.test import MongoTestCase +from utils.test import MongoTestCase, mock_in_memory_image class StructureTests(MongoTestCase): @@ -252,14 +252,16 @@ class StructureTests(MongoTestCase): self.assertEqual(img, structure.groups[0].fields[0].img) def test_save_field_image(self): - img = "soy una imagen de verdad!!" + img_name = "img_test.jpg" + img = mock_in_memory_image(name=img_name) poll = self.poll data = self.data - data['groups']['0']['fields']['0']['img'] = img + data['groups']['0']['fields']['0']['uploaded_file'] = img structure = Structure(data=data, poll=poll) s_id = structure.save() structure = Structure.get(id=s_id) - self.assertEqual(img, structure.groups[0].fields[0].img) + self.assertEqual( + img_name, structure.groups[0].fields[0].get_img_name()) diff --git a/webapp/polls/views.py b/webapp/polls/views.py index 9a5a631..a2239a3 100644 --- a/webapp/polls/views.py +++ b/webapp/polls/views.py @@ -230,6 +230,7 @@ class StructureFormView(TemplateView): if structure.is_valid(new_data=data): try: structure.save_image_options(tmp=False) + structure.save_image_fields() structure.save() except Exception: msg = u'Ocurrió un error, no se guardó la estructura.' @@ -254,6 +255,7 @@ class StructureFormView(TemplateView): ) else: structure.save_image_options(tmp=True) + structure.save_image_fields() context.update({'errors': structure.errors}) messages.add_message( self.request, diff --git a/webapp/webapp/media/images/empty b/webapp/webapp/media/images/empty new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/webapp/webapp/media/images/empty diff --git a/webapp/webapp/settings.py b/webapp/webapp/settings.py index 218ed8a..afdde63 100644 --- a/webapp/webapp/settings.py +++ b/webapp/webapp/settings.py @@ -208,10 +208,14 @@ JASMINE_TEST_DIRECTORY = PROJECT_ROOT + '/../js_tests/' IMAGE_OPTIONS_ROOT = MEDIA_ROOT + 'image_options' +IMAGES_ROOT = MEDIA_ROOT + 'images' + RESULT_BCK_ROOT = MEDIA_ROOT + 'results_bck' IMAGE_OPTIONS_MEDIA_URL = MEDIA_URL + 'image_options' +IMAGES_MEDIA_URL = MEDIA_URL + 'images' + THUMBNAIL_DEBUG = True try: diff --git a/webapp/webapp/static/js/factoryField.js b/webapp/webapp/static/js/factoryField.js index 1834e49..c5b98bd 100644 --- a/webapp/webapp/static/js/factoryField.js +++ b/webapp/webapp/static/js/factoryField.js @@ -58,7 +58,8 @@ "visible_errors": errors.length, "WIDGET_TYPES": widget_types, "dependence_forms": dependence_forms, - "img_src": value['img_src'] + "img_src": IMAGE_MEDIA_URL + "/" + value['img'], + "img_name": value['img'] })); remove_button = field_widget.find('.WField_remove'); bindFieldRemoveButton(remove_button); |