# This file is part of FNP-Redakcja, licensed under GNU Affero GPLv3 or later.
# Copyright © Fundacja Nowoczesna Polska. See NOTICE for more information.
#
-import json
-import re
-from urllib2 import urlopen
from django import forms
from django.utils.translation import ugettext_lazy as _, ugettext
from cover.models import Image
from django.utils.text import mark_safe
+from cover.utils import get_flickr_data, FlickrError
+
+
class ImageAddForm(forms.ModelForm):
class Meta:
model = Image
pass
else:
raise forms.ValidationError(mark_safe(
- ugettext('Image <a href="%(url)s">already in repository</a>.'
- ) % {'url': img.get_absolute_url()}))
+ ugettext('Image <a href="%(url)s">already in repository</a>.')
+ % {'url': img.get_absolute_url()}))
return cl
def clean(self):
raise forms.ValidationError('No image specified')
return cleaned_data
+
class ImageEditForm(forms.ModelForm):
"""Form used for editing a Book."""
class Meta:
"""Form used for not editing an Image."""
def __init__(self, *args, **kwargs):
- ret = super(ReadonlyImageEditForm, self).__init__(*args, **kwargs)
+ super(ReadonlyImageEditForm, self).__init__(*args, **kwargs)
for field in self.fields.values():
field.widget.attrs.update({"readonly": True})
- return ret
def save(self, *args, **kwargs):
- raise AssertionError, "ReadonlyImageEditForm should not be saved."
+ raise AssertionError("ReadonlyImageEditForm should not be saved.")
class FlickrForm(forms.Form):
source_url = forms.URLField(label=_('Flickr URL'))
def clean_source_url(self):
- def normalize_html(html):
- return html
- return re.sub('[\t\n]', '', html)
-
url = self.cleaned_data['source_url']
- m = re.match(r'(https?://)?(www\.|secure\.)?flickr\.com/photos/(?P<author>[^/]+)/(?P<img>\d+)/?', url)
- if not m:
- raise forms.ValidationError("It doesn't look like Flickr URL.")
- author_slug, img_id = m.group('author'), m.group('img')
- base_url = "https://www.flickr.com/photos/%s/%s/" % (author_slug, img_id)
-
- try:
- html = normalize_html(urlopen(url).read().decode('utf-8'))
- except:
- raise forms.ValidationError('Error reading page.')
- match = re.search(r'<a href="([^"]*)"[^>]* rel="license ', html)
- try:
- assert match
- license_url = match.group(1)
- self.cleaned_data['license_url'] = license_url
- re_license = re.compile(r'https?://creativecommons.org/licenses/([^/]*)/([^/]*)/.*')
- m = re_license.match(license_url)
- assert m
- self.cleaned_data['license_name'] = 'CC %s %s' % (m.group(1).upper(), m.group(2))
- except AssertionError:
- raise forms.ValidationError('Error reading license name.')
-
- m = re.search(r'<a[^>]* class="owner-name [^>]*>([^<]*)<', html)
- if m:
- self.cleaned_data['author'] = "%s@Flickr" % m.group(1)
- else:
- raise forms.ValidationError('Error reading author name.')
-
- m = re.search(r'<h1[^>]*>(.*?)</h1>', html, re.S)
- if not m:
- raise forms.ValidationError('Error reading image title.')
- self.cleaned_data['title'] = m.group(1).strip()
-
- m = re.search(r'modelExport: (\{.*\})', html)
try:
- assert m
- self.cleaned_data['download_url'] = 'https:' + json.loads(m.group(1))['photo-models'][0]['sizes']['o']['url']
- except (AssertionError, ValueError, IndexError, KeyError):
- raise forms.ValidationError('Error reading image URL.')
- return base_url
+ flickr_data = get_flickr_data(url)
+ except FlickrError as e:
+ raise forms.ValidationError(e)
+ for field_name in ('license_url', 'license_name', 'author', 'title', 'download_url'):
+ self.cleaned_data[field_name] = flickr_data[field_name]
+ return flickr_data['source_url']
--- /dev/null
+# -*- coding: utf-8 -*-
+# This file is part of Wolnelektury, licensed under GNU Affero GPLv3 or later.
+# Copyright © Fundacja Nowoczesna Polska. See NOTICE for more information.
+#
--- /dev/null
+# -*- coding: utf-8 -*-
+# This file is part of Wolnelektury, licensed under GNU Affero GPLv3 or later.
+# Copyright © Fundacja Nowoczesna Polska. See NOTICE for more information.
+#
--- /dev/null
+# -*- coding: utf-8 -*-
+#
+# This file is part of FNP-Redakcja, licensed under GNU Affero GPLv3 or later.
+# Copyright © Fundacja Nowoczesna Polska. See NOTICE for more information.
+#
+import urllib2 as urllib
+
+from django.core.files.base import ContentFile
+from django.core.management.base import NoArgsCommand
+
+from cover.models import Image
+from cover.utils import get_flickr_data, URLOpener, FlickrError
+
+
+class Command(NoArgsCommand):
+ def handle_noargs(self, **options):
+ for image in Image.objects.exclude(book=None).order_by('id'):
+ print image.id
+ if 'flickr.com' in image.source_url:
+ try:
+ flickr_data = get_flickr_data(image.source_url)
+ except FlickrError as e:
+ print 'Flickr analysis failed: %s' % e
+ else:
+ try:
+ t = URLOpener().open(image.download_url).read()
+ except urllib.URLError:
+ print 'Broken download url'
+ except IOError:
+ print 'Connection failed'
+ else:
+ image.download_url = flickr_data['download_url']
+ image.file.save(image.file.name, ContentFile(t))
+ image.save()
# This file is part of FNP-Redakcja, licensed under GNU Affero GPLv3 or later.
# Copyright © Fundacja Nowoczesna Polska. See NOTICE for more information.
#
-import re
-from urlparse import urljoin
-from django.conf import settings
from django.core.files.base import ContentFile
+from django.core.files.storage import FileSystemStorage
from django.db import models
from django.db.models.signals import post_save
from django.dispatch import receiver
from cover.utils import URLOpener
+class OverwriteStorage(FileSystemStorage):
+
+ def get_available_name(self, name, max_length=None):
+ self.delete(name)
+ return name
+
+
class Image(models.Model):
title = models.CharField(max_length=255, verbose_name=_('title'))
author = models.CharField(max_length=255, verbose_name=_('author'))
license_url = models.URLField(max_length=255, blank=True, verbose_name=_('license URL'))
source_url = models.URLField(verbose_name=_('source URL'), null=True, blank=True)
download_url = models.URLField(unique=True, verbose_name=_('image download URL'), null=True, blank=True)
- file = models.ImageField(upload_to='cover/image', editable=True, verbose_name=_('file'))
+ file = models.ImageField(
+ upload_to='cover/image', storage=OverwriteStorage(), editable=True, verbose_name=_('file'))
class Meta:
verbose_name = _('cover image')
@models.permalink
def get_absolute_url(self):
- return ('cover_image', [self.id])
+ return 'cover_image', [self.id]
def get_full_url(self):
return "http://%s%s" % (Site.objects.get_current().domain, self.get_absolute_url())
if instance.pk and not instance.file:
t = URLOpener().open(instance.download_url).read()
instance.file.save("%d.jpg" % instance.pk, ContentFile(t))
-
-
# This file is part of FNP-Redakcja, licensed under GNU Affero GPLv3 or later.
# Copyright © Fundacja Nowoczesna Polska. See NOTICE for more information.
#
+import json
+import re
from urllib import FancyURLopener
+
from django.contrib.sites.models import Site
@property
def version(self):
return 'FNP Redakcja (http://%s)' % Site.objects.get_current()
+
+
+class FlickrError(Exception):
+ pass
+
+
+def get_flickr_data(url):
+ m = re.match(r'(https?://)?(www\.|secure\.)?flickr\.com/photos/(?P<author>[^/]+)/(?P<img>\d+)/?', url)
+ if not m:
+ raise FlickrError("It doesn't look like Flickr URL.")
+ author_slug, img_id = m.group('author'), m.group('img')
+ base_url = "https://www.flickr.com/photos/%s/%s/" % (author_slug, img_id)
+ try:
+ html = URLOpener().open(url).read().decode('utf-8')
+ except IOError:
+ raise FlickrError('Error reading page')
+ match = re.search(r'<a href="([^"]*)"[^>]* rel="license ', html)
+ if not match:
+ raise FlickrError('License not found.')
+ else:
+ license_url = match.group(1)
+ re_license = re.compile(r'https?://creativecommons.org/licenses/([^/]*)/([^/]*)/.*')
+ m = re_license.match(license_url)
+ if not m:
+ raise FlickrError('License does not look like CC: %s' % license_url)
+ license_name = 'CC %s %s' % (m.group(1).upper(), m.group(2))
+ m = re.search(r'<a[^>]* class="owner-name [^>]*>([^<]*)<', html)
+ if m:
+ author = "%s@Flickr" % m.group(1)
+ else:
+ raise FlickrError('Error reading author name.')
+ m = re.search(r'<h1[^>]*>(.*?)</h1>', html, re.S)
+ if not m:
+ raise FlickrError('Error reading image title.')
+ title = m.group(1).strip()
+ m = re.search(r'modelExport: (\{.*\})', html)
+ try:
+ assert m
+ download_url = 'https:' + json.loads(m.group(1))['photo-models'][0]['sizes']['o']['url']
+ except (AssertionError, ValueError, IndexError, KeyError):
+ raise FlickrError('Error reading image URL.')
+ return {
+ 'source_url': base_url,
+ 'license_url': license_url,
+ 'license_name': license_name,
+ 'author': author,
+ 'title': title,
+ 'download_url': download_url,
+ }
from cover.models import Image
from cover import forms
-
PREVIEW_SIZE = (216, 300)
@active_tab('cover')
def image_list(request):
- objects = Image.objects.all()
- enable_add = request.user.has_perm('cover.add_image')
return render(request, "cover/image_list.html", {
'object_list': Image.objects.all(),
'can_add': request.user.has_perm('cover.add_image'),