From 4cf9e72c93a6b1fd1af3957c253aa43e134b62d8 Mon Sep 17 00:00:00 2001 From: Oliver Falk Date: Tue, 10 Jul 2018 13:18:11 +0200 Subject: [PATCH 1/4] Do allow importing photo from confirmed email --- .../templates/_import_photo_form.html | 29 ++++++++ .../templates/assign_photo_email.html | 7 +- .../templates/email_confirmed.html | 25 +------ .../ivataraccount/templates/import_photo.html | 14 ++++ ivatar/ivataraccount/views.py | 71 +++++++++++-------- 5 files changed, 92 insertions(+), 54 deletions(-) create mode 100644 ivatar/ivataraccount/templates/_import_photo_form.html create mode 100644 ivatar/ivataraccount/templates/import_photo.html diff --git a/ivatar/ivataraccount/templates/_import_photo_form.html b/ivatar/ivataraccount/templates/_import_photo_form.html new file mode 100644 index 0000000..ba3964c --- /dev/null +++ b/ivatar/ivataraccount/templates/_import_photo_form.html @@ -0,0 +1,29 @@ +{% load i18n %} +{% load bootstrap4 %} + +{% if not user.is_anonymous %} + {% if photos %} +

{% trans 'Would you like to import some of these externally hosted photos?' %}

+
{% csrf_token %} + + +

+ {% buttons %} + + {% endbuttons %} +

+
+ {% endif %} +{% endif %} diff --git a/ivatar/ivataraccount/templates/assign_photo_email.html b/ivatar/ivataraccount/templates/assign_photo_email.html index d5961e7..472adbb 100644 --- a/ivatar/ivataraccount/templates/assign_photo_email.html +++ b/ivatar/ivataraccount/templates/assign_photo_email.html @@ -37,7 +37,12 @@ -

{% blocktrans %}upload a new one{% endblocktrans %}

+

+
+ {% blocktrans %}Upload a new one{% endblocktrans %} +
+ {% blocktrans %}Import from other services{% endblocktrans %} +

{% endif %} diff --git a/ivatar/ivataraccount/templates/email_confirmed.html b/ivatar/ivataraccount/templates/email_confirmed.html index 2d54ec5..8f7aec7 100644 --- a/ivatar/ivataraccount/templates/email_confirmed.html +++ b/ivatar/ivataraccount/templates/email_confirmed.html @@ -9,31 +9,8 @@

{% trans 'Your email address was successfully confirmed!' %}

-{% if not user.is_anonymous %} -{% if photos %} - -

{% trans 'Would you like to import some of these externally hosted photos?' %}

-
{% csrf_token %} - - - -

-
-{% endif %} +{% include '_import_photo_form.html' %}

{% trans 'Back to your profile' %}

-{% endif %} {% endblock content %} diff --git a/ivatar/ivataraccount/templates/import_photo.html b/ivatar/ivataraccount/templates/import_photo.html new file mode 100644 index 0000000..60aa898 --- /dev/null +++ b/ivatar/ivataraccount/templates/import_photo.html @@ -0,0 +1,14 @@ +{% extends 'base.html' %} +{% load i18n %} + +{% block title %}{% trans 'Import photo' %} - Libravatar{% endblock title %} + +{% block content %} + +

{% trans 'Import photo' %}

+ +{% include '_import_photo_form.html' %} + +

{% trans 'Back to your profile' %}

+ +{% endblock content %} diff --git a/ivatar/ivataraccount/views.py b/ivatar/ivataraccount/views.py index 591aab5..879c778 100644 --- a/ivatar/ivataraccount/views.py +++ b/ivatar/ivataraccount/views.py @@ -1,6 +1,9 @@ ''' View classes for ivatar/ivataraccount/ ''' + +import io + from django.contrib.auth.decorators import login_required from django.utils.decorators import method_decorator from django.contrib.messages.views import SuccessMessageMixin @@ -14,23 +17,21 @@ from django.utils.translation import ugettext_lazy as _ from django.http import HttpResponseRedirect, HttpResponse from django.urls import reverse_lazy, reverse from django.shortcuts import render +from django_openid_auth.models import UserOpenID from openid import oidutil from openid.consumer import consumer +from ipware import get_client_ip + +from ivatar.settings import MAX_NUM_PHOTOS, MAX_PHOTO_SIZE + from .forms import AddEmailForm, UploadPhotoForm, AddOpenIDForm from .forms import UpdatePreferenceForm from .models import UnconfirmedEmail, ConfirmedEmail, Photo from .models import UnconfirmedOpenId, ConfirmedOpenId, DjangoOpenIDStore from .models import UserPreference - -from ivatar.settings import MAX_NUM_PHOTOS, MAX_PHOTO_SIZE - -import io - -from ipware import get_client_ip - -from django_openid_auth.models import UserOpenID +from .gravatar import get_photo as get_gravatar_photo def openid_logging(message, level=0): @@ -57,12 +58,12 @@ class CreateView(SuccessMessageMixin, FormView): password=form.cleaned_data['password1']) if user is not None: login(self.request, user) - pref = UserPreference.objects.create(user_id=user.pk) + pref = UserPreference.objects.create(user_id=user.pk) # pylint: disable=no-member pref.save() return HttpResponseRedirect(reverse_lazy('profile')) - else: - return HttpResponseRedirect( - reverse_lazy('login')) # pragma: no cover + + return HttpResponseRedirect( + reverse_lazy('login')) # pragma: no cover @method_decorator(login_required, name='dispatch') @@ -111,11 +112,11 @@ class RemoveUnconfirmedEmailView(SuccessMessageMixin, View): def post(self, request, *args, **kwargs): try: - email = UnconfirmedEmail.objects.get( + email = UnconfirmedEmail.objects.get( # pylint: disable=no-member user=request.user, id=kwargs['email_id']) email.delete() messages.success(request, _('Address removed')) - except UnconfirmedEmail.DoesNotExist: + except UnconfirmedEmail.DoesNotExist: # pylint: disable=no-member messages.error(request, _('Address does not exist')) return HttpResponseRedirect(reverse_lazy('profile')) @@ -136,8 +137,8 @@ class ConfirmEmailView(SuccessMessageMixin, TemplateView): return HttpResponseRedirect(reverse_lazy('profile')) try: - unconfirmed = UnconfirmedEmail.objects.get(verification_key=key) - except UnconfirmedEmail.DoesNotExist: + unconfirmed = UnconfirmedEmail.objects.get(verification_key=key) # pylint: disable=no-member + except UnconfirmedEmail.DoesNotExist: # pylint: disable=no-member messages.error(request, _('Verification key does not exist')) return HttpResponseRedirect(reverse_lazy('profile')) @@ -172,7 +173,7 @@ class RemoveConfirmedEmailView(SuccessMessageMixin, View): user=request.user, id=kwargs['email_id']) email.delete() messages.success(request, _('Address removed')) - except ConfirmedEmail.DoesNotExist: + except ConfirmedEmail.DoesNotExist: # pylint: disable=no-member messages.error(request, _('Address does not exist')) return HttpResponseRedirect(reverse_lazy('profile')) @@ -193,16 +194,16 @@ class AssignPhotoEmailView(SuccessMessageMixin, TemplateView): return HttpResponseRedirect(reverse_lazy('profile')) try: - photo = self.model.objects.get( + photo = self.model.objects.get( # pylint: disable=no-member id=request.POST['photo_id'], user=request.user) - except self.model.DoesNotExist: + except self.model.DoesNotExist: # pylint: disable=no-member messages.error(request, _('Photo does not exist')) return HttpResponseRedirect(reverse_lazy('profile')) try: email = ConfirmedEmail.objects.get( user=request.user, id=kwargs['email_id']) - except ConfirmedEmail.DoesNotExist: + except ConfirmedEmail.DoesNotExist: # pylint: disable=no-member messages.error(request, _('Invalid request')) return HttpResponseRedirect(reverse_lazy('profile')) @@ -234,16 +235,16 @@ class AssignPhotoOpenIDView(SuccessMessageMixin, TemplateView): return HttpResponseRedirect(reverse_lazy('profile')) try: - photo = self.model.objects.get( + photo = self.model.objects.get( # pylint: disable=no-member id=request.POST['photo_id'], user=request.user) - except self.model.DoesNotExist: + except self.model.DoesNotExist: # pylint: disable=no-member messages.error(request, _('Photo does not exist')) return HttpResponseRedirect(reverse_lazy('profile')) try: - openid = ConfirmedOpenId.objects.get( + openid = ConfirmedOpenId.objects.get( # pylint: disable=no-member user=request.user, id=kwargs['openid_id']) - except ConfirmedOpenId.DoesNotExist: + except ConfirmedOpenId.DoesNotExist: # pylint: disable=no-member messages.error(request, _('Invalid request')) return HttpResponseRedirect(reverse_lazy('profile')) @@ -255,22 +256,34 @@ class AssignPhotoOpenIDView(SuccessMessageMixin, TemplateView): def get_context_data(self, **kwargs): data = super().get_context_data(**kwargs) - data['openid'] = ConfirmedOpenId.objects.get(pk=kwargs['openid_id']) + data['openid'] = ConfirmedOpenId.objects.get(pk=kwargs['openid_id']) # pylint: disable=no-member return data @method_decorator(login_required, name='dispatch') -class ImportPhotoView(SuccessMessageMixin, View): +class ImportPhotoView(SuccessMessageMixin, TemplateView): ''' View class to import a photo from another service Currently only Gravatar is supported ''' + template_name = 'import_photo.html' - def post(self, request, *args, **kwargs): + def get_context_data(self, **kwargs): + context = super().get_context_data(**kwargs) + context['photos'] = [] + gravatar = get_gravatar_photo(ConfirmedEmail.objects.get(pk=kwargs['email_id']).email) + if gravatar: + context['photos'].append(gravatar) + return context + + def post(self, request, *args, **kwargs): # pylint: disable=no-self-use,unused-argument + ''' + Handle post to photo import + ''' try: email = ConfirmedEmail.objects.get( id=kwargs['email_id'], user=request.user) - except Exception as e: + except ConfirmedEmail.DoesNotExist as e: # pylint: disable=no-member messages.error( request, _('Address does not exist')) @@ -301,7 +314,7 @@ class RawImageView(DetailView): model = Photo def get(self, request, *args, **kwargs): - photo = self.model.objects.get(pk=kwargs['pk']) + photo = self.model.objects.get(pk=kwargs['pk']) # pylint: disable=no-member return HttpResponse( io.BytesIO(photo.data), content_type='image/%s' % photo.format) From 96237bb47e7571de4dc6d346e6997bffc92165b4 Mon Sep 17 00:00:00 2001 From: Oliver Falk Date: Tue, 10 Jul 2018 14:46:30 +0200 Subject: [PATCH 2/4] Ability to import from libravatar + import by email; Forms are WIP! --- ivatar/ivataraccount/models.py | 5 + .../templates/_import_photo_form.html | 14 ++- .../ivataraccount/templates/import_photo.html | 13 +++ ivatar/ivataraccount/urls.py | 6 ++ ivatar/ivataraccount/views.py | 91 ++++++++++++++++--- ivatar/views.py | 10 +- 6 files changed, 119 insertions(+), 20 deletions(-) diff --git a/ivatar/ivataraccount/models.py b/ivatar/ivataraccount/models.py index 6a06fb2..a271a79 100644 --- a/ivatar/ivataraccount/models.py +++ b/ivatar/ivataraccount/models.py @@ -24,6 +24,8 @@ from openid.association import Association as OIDAssociation from openid.store import nonce as oidnonce from openid.store.interface import OpenIDStore +from libravatar import libravatar_url + from ivatar.settings import MAX_LENGTH_EMAIL, logger from ivatar.settings import MAX_PIXELS, AVATAR_MAX_SIZE, JPEG_QUALITY from ivatar.settings import MIN_LENGTH_URL, MAX_LENGTH_URL @@ -127,6 +129,9 @@ class Photo(BaseAccountModel): if gravatar: image_url = gravatar['image_url'] + if service_name == 'Libravatar': + image_url = libravatar_url(email_address) + if not image_url: return False # pragma: no cover try: diff --git a/ivatar/ivataraccount/templates/_import_photo_form.html b/ivatar/ivataraccount/templates/_import_photo_form.html index ba3964c..3098117 100644 --- a/ivatar/ivataraccount/templates/_import_photo_form.html +++ b/ivatar/ivataraccount/templates/_import_photo_form.html @@ -4,12 +4,20 @@ {% if not user.is_anonymous %} {% if photos %}

{% trans 'Would you like to import some of these externally hosted photos?' %}

-
{% csrf_token %} + {% if email_id %} + {% csrf_token %} + {% else %} + {% csrf_token %} + + {% endif %}
    {% for photo in photos %}
  • -
    +
    +
    {% if photo.service_url %} {{ photo.service_name }} @@ -25,5 +33,7 @@ {% endbuttons %}

  • + {% else %} +

    {% trans 'Nothing importable found' %}

    {% endif %} {% endif %} diff --git a/ivatar/ivataraccount/templates/import_photo.html b/ivatar/ivataraccount/templates/import_photo.html index 60aa898..a7f17e0 100644 --- a/ivatar/ivataraccount/templates/import_photo.html +++ b/ivatar/ivataraccount/templates/import_photo.html @@ -1,5 +1,6 @@ {% extends 'base.html' %} {% load i18n %} +{% load bootstrap4 %} {% block title %}{% trans 'Import photo' %} - Libravatar{% endblock title %} @@ -9,6 +10,18 @@ {% include '_import_photo_form.html' %} +{# Code not ready yet +{% if not email_id %} +
    {% csrf_token %} + + + {% buttons %} + + {% endbuttons %} +
    +{% endif %} +#} +

    {% trans 'Back to your profile' %}

    {% endblock content %} diff --git a/ivatar/ivataraccount/urls.py b/ivatar/ivataraccount/urls.py index fb64a66..8b03d38 100644 --- a/ivatar/ivataraccount/urls.py +++ b/ivatar/ivataraccount/urls.py @@ -66,6 +66,12 @@ urlpatterns = [ # pylint: disable=invalid-name url( r'assign_photo_openid/(?P\d+)', AssignPhotoOpenIDView.as_view(), name='assign_photo_openid'), + url( + r'import_photo/$', + ImportPhotoView.as_view(), name='import_photo'), + url( + r'import_photo/(?P[\w.]+@[\w.]+.[\w.]+)', + ImportPhotoView.as_view(), name='import_photo'), url( r'import_photo/(?P\d+)', ImportPhotoView.as_view(), name='import_photo'), diff --git a/ivatar/ivataraccount/views.py b/ivatar/ivataraccount/views.py index 879c778..abe0491 100644 --- a/ivatar/ivataraccount/views.py +++ b/ivatar/ivataraccount/views.py @@ -3,6 +3,7 @@ View classes for ivatar/ivataraccount/ ''' import io +from urllib.request import urlopen from django.contrib.auth.decorators import login_required from django.utils.decorators import method_decorator @@ -24,6 +25,8 @@ from openid.consumer import consumer from ipware import get_client_ip +from libravatar import libravatar_url + from ivatar.settings import MAX_NUM_PHOTOS, MAX_PHOTO_SIZE from .forms import AddEmailForm, UploadPhotoForm, AddOpenIDForm @@ -271,37 +274,95 @@ class ImportPhotoView(SuccessMessageMixin, TemplateView): def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) context['photos'] = [] - gravatar = get_gravatar_photo(ConfirmedEmail.objects.get(pk=kwargs['email_id']).email) - if gravatar: - context['photos'].append(gravatar) + addr = None + if 'email_id' in kwargs: + addr = ConfirmedEmail.objects.get(pk=kwargs['email_id']).email + if 'email_addr' in kwargs: + addr = kwargs['email_addr'] + + if addr: + gravatar = get_gravatar_photo(addr) + if gravatar: + context['photos'].append(gravatar) + + libravatar_service_url = libravatar_url( + email=addr, + default=404, + ) + try: + if libravatar_service_url: + response = urlopen(libravatar_service_url) + context['photos'].append({ + 'service_url': libravatar_service_url, + 'thumbnail_url': libravatar_service_url + '?s=80', + 'image_url': libravatar_service_url + '?s=512', + 'width': 80, + 'height': 80, + 'service_name': 'Libravatar', + }) + except Exception: + pass + return context def post(self, request, *args, **kwargs): # pylint: disable=no-self-use,unused-argument ''' Handle post to photo import ''' - try: - email = ConfirmedEmail.objects.get( - id=kwargs['email_id'], user=request.user) - except ConfirmedEmail.DoesNotExist as e: # pylint: disable=no-member - messages.error( - request, - _('Address does not exist')) - return HttpResponseRedirect(reverse_lazy('profile')) + + addr = None + email_id = None + imported = None + + if 'email_id' in kwargs: + email_id = kwargs['email_id'] + if 'email_id' in request.POST: + email_id = request.POST['email_id'] + if 'email_addr' in kwargs: + addr = kwargs['email_addr'] + if 'email_addr' in request.POST: + addr = request.POST['email_addr'] + + if email_id: + try: + email = ConfirmedEmail.objects.filter( + id=email_id, user=request.user) + if email.count() > 0: + addr = email.first().email + except ConfirmedEmail.DoesNotExist: # pylint: disable=no-member + messages.error( + request, + _('Address does not exist')) + return HttpResponseRedirect(reverse_lazy('profile')) if 'photo_Gravatar' in request.POST: photo = Photo() photo.user = request.user photo.ip_address = get_client_ip(request) - if photo.import_image('Gravatar', email.email): + if photo.import_image('Gravatar', addr): messages.success(request, - _('Image successfully imported')) + _('Gravatar image successfully imported')) else: # Honestly, I'm not sure how to test this... messages.error( request, - _('Image import not successful')) # pragma: no cover - else: + _('Gravatar image import not successful')) # pragma: no cover + imported = True + + if 'photo_Libravatar' in request.POST: + photo = Photo() + photo.user = request.user + photo.ip_address = get_client_ip(request) + if photo.import_image('Libravatar', addr): + messages.success(request, + _('Libravatar successfully imported')) + else: + # Honestly, I'm not sure how to test this... + messages.error( + request, + _('Libravatar image import not successful')) # pragma: no cover + imported = True + if not imported: messages.warning(request, _('Nothing importable')) return HttpResponseRedirect(reverse_lazy('profile')) diff --git a/ivatar/views.py b/ivatar/views.py index 935cb59..2fe44a1 100644 --- a/ivatar/views.py +++ b/ivatar/views.py @@ -5,8 +5,10 @@ from io import BytesIO from os import path from PIL import Image from django.views.generic.base import TemplateView -from django.http import HttpResponse, HttpResponseRedirect +from django.http import HttpResponse, HttpResponseRedirect, HttpResponseNotFound from django.core.exceptions import ObjectDoesNotExist +from django.utils.translation import ugettext_lazy as _ + from ivatar.settings import AVATAR_MAX_SIZE, JPEG_QUALITY from . ivataraccount.models import ConfirmedEmail, ConfirmedOpenId from . ivataraccount.models import pil_format @@ -58,10 +60,12 @@ class AvatarImageView(TemplateView): # If that mail/openid doesn't exist, or has no photo linked to it if not obj or not obj.photo: - # Return the default URL, as specified + # Return the default URL, as specified, or 404 Not Found, if default=404 if default: + if str(default) == str(404): + return HttpResponseNotFound(_('

    Image not found

    ')) return HttpResponseRedirect(default) - # Return our default URl + # Return our default URL else: static_img = path.join('static', 'img', 'mm', '%s%s' % (str(size), '.png')) if not path.isfile(static_img): From 0ac96e2ed0936b55abe35090fb04694dd08464a1 Mon Sep 17 00:00:00 2001 From: Oliver Falk Date: Wed, 11 Jul 2018 08:07:56 +0200 Subject: [PATCH 3/4] Finish feature 'import image from other sites' --- .../templates/_import_photo_form.html | 2 -- .../ivataraccount/templates/import_photo.html | 24 ++++++++++++------- ivatar/ivataraccount/templates/profile.html | 6 ++++- ivatar/ivataraccount/views.py | 2 +- 4 files changed, 21 insertions(+), 13 deletions(-) diff --git a/ivatar/ivataraccount/templates/_import_photo_form.html b/ivatar/ivataraccount/templates/_import_photo_form.html index 3098117..d5fcf56 100644 --- a/ivatar/ivataraccount/templates/_import_photo_form.html +++ b/ivatar/ivataraccount/templates/_import_photo_form.html @@ -33,7 +33,5 @@ {% endbuttons %}

    - {% else %} -

    {% trans 'Nothing importable found' %}

    {% endif %} {% endif %} diff --git a/ivatar/ivataraccount/templates/import_photo.html b/ivatar/ivataraccount/templates/import_photo.html index a7f17e0..104c985 100644 --- a/ivatar/ivataraccount/templates/import_photo.html +++ b/ivatar/ivataraccount/templates/import_photo.html @@ -10,17 +10,23 @@ {% include '_import_photo_form.html' %} -{# Code not ready yet {% if not email_id %} -
    {% csrf_token %} - - - {% buttons %} - - {% endbuttons %} -
    +
    + + + {% buttons %} + + {% endbuttons %} +
    + + {% endif %} -#}

    {% trans 'Back to your profile' %}

    diff --git a/ivatar/ivataraccount/templates/profile.html b/ivatar/ivataraccount/templates/profile.html index ad2d4f5..8e0488a 100644 --- a/ivatar/ivataraccount/templates/profile.html +++ b/ivatar/ivataraccount/templates/profile.html @@ -79,7 +79,11 @@ {% endif %} {% if not max_photos %} -

    {% trans 'Upload a new photo' %}

    +

    +
    + {% trans 'Upload a new photo' %}
    + {% trans 'Import photo from other services' %} +

    {% endif %}

    {% trans 'Account settings' %}

    diff --git a/ivatar/ivataraccount/views.py b/ivatar/ivataraccount/views.py index abe0491..51c0a86 100644 --- a/ivatar/ivataraccount/views.py +++ b/ivatar/ivataraccount/views.py @@ -355,7 +355,7 @@ class ImportPhotoView(SuccessMessageMixin, TemplateView): photo.ip_address = get_client_ip(request) if photo.import_image('Libravatar', addr): messages.success(request, - _('Libravatar successfully imported')) + _('Libravatar image successfully imported')) else: # Honestly, I'm not sure how to test this... messages.error( From 7ffd21dee7fe41a5ce6c46b1222c2d9afd8549fb Mon Sep 17 00:00:00 2001 From: Oliver Falk Date: Wed, 11 Jul 2018 09:04:17 +0200 Subject: [PATCH 4/4] Fix tests and eliminate bug, since we use filter now, we cannot depend on an exception raised --- ivatar/ivataraccount/test_views.py | 4 +--- ivatar/ivataraccount/views.py | 20 +++++++++++++------- 2 files changed, 14 insertions(+), 10 deletions(-) diff --git a/ivatar/ivataraccount/test_views.py b/ivatar/ivataraccount/test_views.py index aaf1994..150bf95 100644 --- a/ivatar/ivataraccount/test_views.py +++ b/ivatar/ivataraccount/test_views.py @@ -333,7 +333,7 @@ class Tester(TestCase): # pylint: disable=too-many-public-methods 'unable to import photo from Gravatar?') self.assertEqual( str(list(response.context[0]['messages'])[0]), - 'Image successfully imported', + 'Gravatar image successfully imported', 'Importing gravatar photo did not work?') self.assertIsInstance( self.user.photo_set.first(), @@ -1162,8 +1162,6 @@ class Tester(TestCase): # pylint: disable=too-many-public-methods ) url = '%s?%s' % (urlobj.path, urlobj.query) response = self.client.get(url, follow=False) - print(response) - print(response.content) self.assertRedirects( response=response, expected_url=default, diff --git a/ivatar/ivataraccount/views.py b/ivatar/ivataraccount/views.py index 51c0a86..2f5f733 100644 --- a/ivatar/ivataraccount/views.py +++ b/ivatar/ivataraccount/views.py @@ -276,7 +276,14 @@ class ImportPhotoView(SuccessMessageMixin, TemplateView): context['photos'] = [] addr = None if 'email_id' in kwargs: - addr = ConfirmedEmail.objects.get(pk=kwargs['email_id']).email + try: + addr = ConfirmedEmail.objects.get(pk=kwargs['email_id']).email + except: + messages.error( + self.request, + _('Address does not exist')) + return context + if 'email_addr' in kwargs: addr = kwargs['email_addr'] @@ -324,12 +331,11 @@ class ImportPhotoView(SuccessMessageMixin, TemplateView): addr = request.POST['email_addr'] if email_id: - try: - email = ConfirmedEmail.objects.filter( - id=email_id, user=request.user) - if email.count() > 0: - addr = email.first().email - except ConfirmedEmail.DoesNotExist: # pylint: disable=no-member + email = ConfirmedEmail.objects.filter( + id=email_id, user=request.user) + if email.count() > 0: + addr = email.first().email + else: messages.error( request, _('Address does not exist'))