summaryrefslogtreecommitdiff
path: root/app/photos/forms.py
diff options
context:
space:
mode:
Diffstat (limited to 'app/photos/forms.py')
-rw-r--r--app/photos/forms.py173
1 files changed, 173 insertions, 0 deletions
diff --git a/app/photos/forms.py b/app/photos/forms.py
new file mode 100644
index 0000000..126cfaf
--- /dev/null
+++ b/app/photos/forms.py
@@ -0,0 +1,173 @@
+import zipfile
+from zipfile import BadZipFile
+import logging
+import datetime
+import os
+from io import BytesIO
+try:
+ import Image
+except ImportError:
+ from PIL import Image
+
+from django import forms
+from django.utils.translation import ugettext_lazy as _
+from django.contrib import messages
+from django.core.files.base import ContentFile
+from django.contrib.admin import widgets
+from django.utils.safestring import mark_safe
+
+from photos.models import LuxImage, LuxGallery, LuxImageSize
+
+logger = logging.getLogger('photos.forms')
+
+
+class GalleryForm(forms.ModelForm):
+ class Meta:
+ fields = '__all__'
+ widgets = {
+ 'images': forms.SelectMultiple,
+ }
+
+ def __init__(self, *args, **kwargs):
+ super(GalleryForm, self).__init__(*args, **kwargs)
+ self.fields['images'].choices = [(image.id, mark_safe('%sqq%sqq%s' % (image.title, image.get_image_by_size('tn'), image.pk))) for image in LuxImage.objects.all()[:40]]
+ self.fields['images'].allow_tags = True
+
+
+class ImageChoiceField(forms.ModelMultipleChoiceField):
+
+ def label_from_instance(self, obj):
+
+ return mark_safe('%sqq%sqq%s' % (obj.title, obj.get_image_by_size('tn'), obj.pk))
+
+
+class FKGalleryForm(forms.ModelForm):
+ class Meta:
+ fields = '__all__'
+ widgets = {
+ 'image': ImageChoiceField(queryset=LuxImage.objects.all()),
+ }
+
+ def __init__(self, *args, **kwargs):
+ super(FKGalleryForm, self).__init__(*args, **kwargs)
+ self.fields['image'].choices = [(o.id, str(o.image.url)) for o in LuxImage.objects.all()]
+ self.fields['image'].allow_tags = True
+
+
+class UploadZipForm(forms.Form):
+ """
+ Handles the uploading of a gallery of photos packed in a .zip file
+ Creates Gallery object, adds photos with all metadata that's available
+ """
+ zip_file = forms.FileField()
+ title = forms.CharField(label=_('Gallery Title'), max_length=250)
+ slug = forms.SlugField(label=_('Gallery Slug'))
+ desc = forms.CharField(label=_('Gallery Caption'), widget=forms.Textarea, required=False)
+ date = forms.SplitDateTimeField(label=_('Date'), widget=widgets.AdminSplitDateTime)
+ is_public = forms.BooleanField(label=_('Is public'), initial=True, required=False, help_text=_('Show on site'))
+
+ def clean_zip_file(self):
+ """Open the zip file a first time, to check that it is a valid zip archive.
+ We'll open it again in a moment, so we have some duplication, but let's focus
+ on keeping the code easier to read!
+ """
+ zip_file = self.cleaned_data['zip_file']
+ try:
+ zip = zipfile.ZipFile(zip_file)
+ except BadZipFile as e:
+ raise forms.ValidationError(str(e))
+ bad_file = zip.testzip()
+ if bad_file:
+ zip.close()
+ raise forms.ValidationError('"%s" in the .zip archive is corrupt.' % bad_file)
+ zip.close() # Close file in all cases.
+ return zip_file
+
+ def clean_title(self):
+ title = self.cleaned_data['title']
+ if title and LuxGallery.objects.filter(title=title).exists():
+ raise forms.ValidationError(_('A gallery with that title already exists.'))
+ return title
+
+ def clean(self):
+ cleaned_data = super(UploadZipForm, self).clean()
+ if not self['title'].errors:
+ # If there's already an error in the title, no need to add another
+ # error related to the same field.
+ if not cleaned_data.get('title', None) and not cleaned_data['gallery']:
+ raise forms.ValidationError(
+ _('Select an existing gallery, or enter a title for a new gallery.'))
+ return cleaned_data
+
+ def save(self, request=None, zip_file=None):
+ if not zip_file:
+ zip_file = self.cleaned_data['zip_file']
+
+ gallery, created = LuxGallery.objects.get_or_create(
+ title=self.cleaned_data['title'],
+ description=self.cleaned_data['desc'],
+ slug=self.cleaned_data['slug'],
+ pub_date=self.cleaned_data['date'],
+ is_public=self.cleaned_data['is_public']
+ )
+ zipper = zipfile.ZipFile(zip_file)
+ count = 1
+ for filename in sorted(zipper.namelist()):
+ f, file_extension = os.path.splitext(filename)
+ logger.debug('Reading file "{0}".'.format(filename))
+ if filename.startswith('__') or filename.startswith('.'):
+ logger.debug('Ignoring file "{0}".'.format(filename))
+ continue
+ if os.path.dirname(filename):
+ logger.warning('Ignoring file "{0}" as it is in a subfolder; all images should be in the top '
+ 'folder of the zip.'.format(filename))
+ if request:
+ messages.warning(request,
+ _('Ignoring file "{filename}" as it is in a subfolder').format(filename=filename), fail_silently=True)
+ continue
+ data = zipper.read(filename)
+
+ if not len(data):
+ logger.debug('File "{0}" is empty.'.format(filename))
+ continue
+
+ fn, file_extension = os.path.splitext(filename)
+ if file_extension != ".mp4":
+ # Basic check that we have a valid image.
+ try:
+ file = BytesIO(data)
+ opened = Image.open(file)
+ opened.verify()
+ except Exception:
+ # Pillow (or PIL) doesn't recognize it as an image.
+ # If a "bad" file is found we just skip it.
+ # But we do flag this both in the logs and to the user.
+ logger.error('Could not process file "{0}" in the .zip archive.'.format(filename))
+ if request:
+ messages.warning(request,
+ _('Could not process file "{0}" in the .zip archive.').format(
+ filename),
+ fail_silently=True)
+ continue
+ image = LuxImage(
+ pub_date=datetime.datetime.now()
+ )
+ contentfile = ContentFile(data)
+ image.image.save(filename, contentfile)
+ if file_extension != ".mp4":
+ img = Image.open(image.image.path)
+ if img.size[0] > img.size[1]:
+ image.sizes.add(LuxImageSize.objects.get(width=2560))
+ image.sizes.add(LuxImageSize.objects.get(width=1170))
+ image.sizes.add(LuxImageSize.objects.get(width=720))
+ if img.size[1] > img.size[0]:
+ image.sizes.add(LuxImageSize.objects.get(height=1600))
+ image.sizes.add(LuxImageSize.objects.get(height=800))
+ image.sizes.add(LuxImageSize.objects.get(height=460))
+ image.save()
+ gallery.images.add(image)
+
+ zipper.close()
+
+ if request:
+ messages.success(request, _('The photos have been uploaded'))