Add extra page after libravatar export upload, where user can choose what to import

This commit is contained in:
Oliver Falk
2018-07-13 12:23:58 +02:00
parent 7fc341b24a
commit 973437f923
5 changed files with 122 additions and 55 deletions

View File

@@ -209,43 +209,3 @@ class UploadLibravatarExportForm(forms.Form):
_('This field must be checked since we need to be able to\ _('This field must be checked since we need to be able to\
distribute photos to third parties.') distribute photos to third parties.')
}) })
@staticmethod
def save(request, data):
'''
Save the models and assign it to the current user
'''
items = libravatar_read_gzdata(data.read())
for email in items['emails']:
if not ConfirmedEmail.objects.filter(email=email) and \
not UnconfirmedEmail.objects.filter(email=email): # pylint: disable=no-member
try:
unconfirmed = UnconfirmedEmail.objects.create( # pylint: disable=no-member
user=request.user,
email=email
)
unconfirmed.save()
unconfirmed.send_confirmation_mail(url=request.build_absolute_uri('/')[:-1])
except Exception as e: # pylint: disable=broad-except,invalid-name
# Debugging only
print('Exception while trying to import mail addresses: %s' % e)
if 'openids' in items:
messages.warning(
request,
_('You have OpenIDs in your export file, but we cannot\
import those at the moment'))
for pilobj in items['photos']:
# Is there a reasonable way to check if that photo already exists!?
try:
data = BytesIO()
pilobj.save(data, pilobj.format, quality=JPEG_QUALITY)
data.seek(0)
photo = Photo()
photo.user = request.user
photo.ip_address = get_client_ip(request)[0]
photo.format = file_format(pilobj.format)
photo.data = data.read()
photo.save()
except Exception: # pylint: disable=broad-except
pass

View File

@@ -49,14 +49,18 @@ def read_gzdata(gzdata=None):
photo.attrib['encoding'], photo.attrib['format'], e)) photo.attrib['encoding'], photo.attrib['format'], e))
continue continue
try: try:
img = Image.open(BytesIO(data)) Image.open(BytesIO(data))
# If it is a working image, we can use it
photo.text.replace('\n', '')
photos.append({
'data': photo.text,
'format': photo.attrib['format'],
})
except Exception as e: # pylint: disable=broad-except,invalid-name except Exception as e: # pylint: disable=broad-except,invalid-name
print('Cannot decode photo; Encoding: %s, Format: %s: %s' % ( print('Cannot decode photo; Encoding: %s, Format: %s: %s' % (
photo.attrib['encoding'], photo.attrib['format'], e)) photo.attrib['encoding'], photo.attrib['format'], e))
continue continue
photos.append(img)
return { return {
'emails': emails, 'emails': emails,
'openids': openids, 'openids': openids,

View File

@@ -0,0 +1,40 @@
{% extends 'base.html' %}
{% load i18n %}
{% load static %}
{% load bootstrap4 %}
{% block title %}{% trans 'Choose items to be uploaded' %}{% endblock title %}
{% block content %}
<h1>{% trans 'Choose items to be imported' %}</h1>
<div style="max-width:600px;">
<form method="post" action="{% url 'upload_export' 'save' %}">{% csrf_token %}
{% if emails %}
<p>
{% trans 'Email addresses we found in the export - existing ones will not be re-added' %}:
</p>
{% for email in emails %}
<input type="checkbox" checked name="email_{{ forloop.counter }}" value="{{ email }}"> {{ email }}</input><br/>
{% endfor %}
{% endif %}
<p/>
{% if photos %}
<p>
{% trans 'Photos we found in the export' %}:
</p>
{% for photo in photos %}
<input type="checkbox" checked name="photo_{{ forloop.counter }}" value="{{ photo.data }}">
<img style="max-width: 80px; max-height: 80px;" src="data:image/{{ photo.format }};base64,{{ photo.data }}"/>
</input>
<br/>
{% endfor %}
{% endif %}
<br/>
{% buttons %}
<button type="submit" class="btn btn-primary">{% trans 'Upload' %}</button>
<button type="cancel" class="btn btn-danger">{% trans 'Cancel' %}</button>
{% endbuttons %}
</form>
</div>
{% endblock content %}

View File

@@ -85,4 +85,6 @@ urlpatterns = [ # pylint: disable=invalid-name
url(r'crop_photo/(?P<pk>\d+)', CropPhotoView.as_view(), name='crop_photo'), url(r'crop_photo/(?P<pk>\d+)', CropPhotoView.as_view(), name='crop_photo'),
url(r'pref/$', UserPreferenceView.as_view(), name='user_preference'), url(r'pref/$', UserPreferenceView.as_view(), name='user_preference'),
url(r'upload_export/$', UploadLibravatarExportView.as_view(), name='upload_export'), url(r'upload_export/$', UploadLibravatarExportView.as_view(), name='upload_export'),
url(r'upload_export/(?P<save>save)$',
UploadLibravatarExportView.as_view(), name='upload_export'),
] ]

View File

@@ -1,8 +1,11 @@
''' '''
View classes for ivatar/ivataraccount/ View classes for ivatar/ivataraccount/
''' '''
import io from io import BytesIO
from urllib.request import urlopen from urllib.request import urlopen
import base64
from PIL import Image
from django.contrib.auth.decorators import login_required from django.contrib.auth.decorators import login_required
from django.contrib.auth.models import User from django.contrib.auth.models import User
@@ -20,22 +23,22 @@ from django.urls import reverse_lazy, reverse
from django.shortcuts import render from django.shortcuts import render
from django_openid_auth.models import UserOpenID from django_openid_auth.models import UserOpenID
from django_openid_auth.models import UserOpenID
from openid import oidutil from openid import oidutil
from openid.consumer import consumer from openid.consumer import consumer
from ipware import get_client_ip from ipware import get_client_ip
from libravatar import libravatar_url from libravatar import libravatar_url
from ivatar.settings import MAX_NUM_PHOTOS, MAX_PHOTO_SIZE, JPEG_QUALITY
from .gravatar import get_photo as get_gravatar_photo from .gravatar import get_photo as get_gravatar_photo
from ivatar.settings import MAX_NUM_PHOTOS, MAX_PHOTO_SIZE
from .forms import AddEmailForm, UploadPhotoForm, AddOpenIDForm from .forms import AddEmailForm, UploadPhotoForm, AddOpenIDForm
from .forms import UpdatePreferenceForm, UploadLibravatarExportForm from .forms import UpdatePreferenceForm, UploadLibravatarExportForm
from .models import UnconfirmedEmail, ConfirmedEmail, Photo from .models import UnconfirmedEmail, ConfirmedEmail, Photo
from .models import UnconfirmedOpenId, ConfirmedOpenId, DjangoOpenIDStore from .models import UnconfirmedOpenId, ConfirmedOpenId, DjangoOpenIDStore
from .models import UserPreference from .models import UserPreference
from .models import file_format
from . read_libravatar_export import read_gzdata as libravatar_read_gzdata
def openid_logging(message, level=0): def openid_logging(message, level=0):
@@ -295,7 +298,7 @@ class ImportPhotoView(SuccessMessageMixin, TemplateView):
if 'email_id' in kwargs: if 'email_id' in kwargs:
try: try:
addr = ConfirmedEmail.objects.get(pk=kwargs['email_id']).email addr = ConfirmedEmail.objects.get(pk=kwargs['email_id']).email
except: except Exception: # pylint: disable=broad-except
messages.error( messages.error(
self.request, self.request,
_('Address does not exist')) _('Address does not exist'))
@@ -315,7 +318,8 @@ class ImportPhotoView(SuccessMessageMixin, TemplateView):
) )
try: try:
if libravatar_service_url: if libravatar_service_url:
response = urlopen(libravatar_service_url) # if it doesn't work, it will be catched by except
urlopen(libravatar_service_url)
context['photos'].append({ context['photos'].append({
'service_url': libravatar_service_url, 'service_url': libravatar_service_url,
'thumbnail_url': libravatar_service_url + '?s=80', 'thumbnail_url': libravatar_service_url + '?s=80',
@@ -324,12 +328,13 @@ class ImportPhotoView(SuccessMessageMixin, TemplateView):
'height': 80, 'height': 80,
'service_name': 'Libravatar', 'service_name': 'Libravatar',
}) })
except Exception: except Exception as e: # pylint: disable=broad-except,invalid-name
print('Exception caught during photo import: %s' % e)
pass pass
return context return context
def post(self, request, *args, **kwargs): # pylint: disable=no-self-use,unused-argument def post(self, request, *args, **kwargs): # pylint: disable=no-self-use,unused-argument,too-many-branches
''' '''
Handle post to photo import Handle post to photo import
''' '''
@@ -400,7 +405,7 @@ class RawImageView(DetailView):
def get(self, request, *args, **kwargs): def get(self, request, *args, **kwargs):
photo = self.model.objects.get(pk=kwargs['pk']) # pylint: disable=no-member photo = self.model.objects.get(pk=kwargs['pk']) # pylint: disable=no-member
return HttpResponse( return HttpResponse(
io.BytesIO(photo.data), content_type='image/%s' % photo.format) BytesIO(photo.data), content_type='image/%s' % photo.format)
@method_decorator(login_required, name='dispatch') @method_decorator(login_required, name='dispatch')
@@ -717,8 +722,64 @@ class UploadLibravatarExportView(SuccessMessageMixin, FormView):
success_url = reverse_lazy('profile') success_url = reverse_lazy('profile')
model = User model = User
def post(self, request, *args, **kwargs): # pylint: disable=unused-argument
'''
Handle post request - choose items to import
'''
if 'save' in kwargs: # pylint: disable=too-many-nested-blocks
if kwargs['save'] == 'save':
for arg in request.POST:
if arg.startswith('email_'):
email = request.POST[arg]
if not ConfirmedEmail.objects.filter(email=email) and \
not UnconfirmedEmail.objects.filter(email=email): # pylint: disable=no-member
try:
unconfirmed = UnconfirmedEmail.objects.create( # pylint: disable=no-member
user=request.user,
email=email
)
unconfirmed.save()
unconfirmed.send_confirmation_mail(
url=request.build_absolute_uri('/')[:-1])
messages.info(
request,
'%s: %s' %(
email,
_('address added successfully,\
confirmation mail sent')))
except Exception as e: # pylint: disable=broad-except,invalid-name
# DEBUG
print('Exception during adding mail address (%s): %s' % (email, e))
if arg.startswith('photo'):
try:
data = base64.decodebytes(bytes(request.POST[arg], 'utf-8'))
except Exception as e: # pylint: disable=broad-except,invalid-name
print('Cannot decode photo: %s' % e)
continue
try:
pilobj = Image.open(BytesIO(data))
out = BytesIO()
pilobj.save(out, pilobj.format, quality=JPEG_QUALITY)
out.seek(0)
photo = Photo()
photo.user = request.user
photo.ip_address = get_client_ip(request)[0]
photo.format = file_format(pilobj.format)
photo.data = out.read()
photo.save()
except Exception as e: # pylint: disable=broad-except,invalid-name
print('Exception during save: %s' % e)
continue
return HttpResponseRedirect(reverse_lazy('profile'))
return super().post(request, args, kwargs)
def form_valid(self, form): def form_valid(self, form):
data = self.request.FILES['export_file'] data = self.request.FILES['export_file']
items = libravatar_read_gzdata(data.read())
form.save(self.request, data) # DEBUG print(items)
return super().form_valid(form) return render(self.request, 'choose_libravatar_export.html', {
'emails': items['emails'],
'photos': items['photos'],
})