From 24727f55910018b9d09136e16f01a3fa8fee118a Mon Sep 17 00:00:00 2001 From: Oliver Falk Date: Wed, 27 Jun 2018 07:36:21 +0200 Subject: [PATCH 1/9] OOps, need to check in the right model of course --- ivatar/views.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ivatar/views.py b/ivatar/views.py index cc5b9ed..dba0573 100644 --- a/ivatar/views.py +++ b/ivatar/views.py @@ -22,7 +22,7 @@ class AvatarImageView(TemplateView): # Fetch by digest from mail pass elif len(kwargs['digest']) == 64: - if model.objects.filter(digest=kwargs['digest']).count(): + if ConfirmedOpenId.objects.filter(digest=kwargs['digest']).count(): # Fetch by digest from OpenID model = ConfirmedOpenId else: # pragma: no cover From 8efbcc7ebcc28cc03978f41e8285f55d5d3acc47 Mon Sep 17 00:00:00 2001 From: Oliver Falk Date: Wed, 27 Jun 2018 08:29:39 +0200 Subject: [PATCH 2/9] Avoid deleting photo cascades and deletes mail/openid and make sure digest_sha256 may not be null (needs migration 0007) --- ivatar/ivataraccount/models.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/ivatar/ivataraccount/models.py b/ivatar/ivataraccount/models.py index 71b756a..b73cc2f 100644 --- a/ivatar/ivataraccount/models.py +++ b/ivatar/ivataraccount/models.py @@ -257,10 +257,10 @@ class ConfirmedEmail(BaseAccountModel): related_name='emails', blank=True, null=True, - on_delete=models.deletion.CASCADE, + on_delete=models.deletion.SET_NULL, ) digest = models.CharField(max_length=32) - digest_sha256 = models.CharField(max_length=64, null=True) + digest_sha256 = models.CharField(max_length=64) objects = ConfirmedEmailManager() class Meta: # pylint: disable=too-few-public-methods @@ -336,7 +336,7 @@ class ConfirmedOpenId(BaseAccountModel): related_name='openids', blank=True, null=True, - on_delete=models.deletion.CASCADE, + on_delete=models.deletion.SET_NULL, ) digest = models.CharField(max_length=64) From 1869da2dfa36c0eae40aeb3c81d127f43b822f32 Mon Sep 17 00:00:00 2001 From: Oliver Falk Date: Wed, 27 Jun 2018 08:31:06 +0200 Subject: [PATCH 3/9] Migration for digest_sha256 != NULL and no cascading deletion --- .../migrations/0007_auto_20180627_0624.py | 39 +++++++++++++++++++ 1 file changed, 39 insertions(+) create mode 100644 ivatar/ivataraccount/migrations/0007_auto_20180627_0624.py diff --git a/ivatar/ivataraccount/migrations/0007_auto_20180627_0624.py b/ivatar/ivataraccount/migrations/0007_auto_20180627_0624.py new file mode 100644 index 0000000..97b3509 --- /dev/null +++ b/ivatar/ivataraccount/migrations/0007_auto_20180627_0624.py @@ -0,0 +1,39 @@ +# Generated by Django 2.0.6 on 2018-06-27 06:24 + +from django.db import migrations, models +import django.db.models.deletion + +def add_sha256(apps, schema_editor): + ''' + Make sure all ConfirmedEmail have digest_sha256 set + in order to alter the model so sha256 may not be NULL + ''' + ConfirmedEmail = apps.get_model('ivataraccount', 'ConfirmedEmail') + for mail in ConfirmedEmail.objects.filter(digest_sha256=None): + mail.save() + + +class Migration(migrations.Migration): + + dependencies = [ + ('ivataraccount', '0006_auto_20180626_1445'), + ] + + operations = [ + migrations.RunPython(add_sha256), + migrations.AlterField( + model_name='confirmedemail', + name='digest_sha256', + field=models.CharField(max_length=64), + ), + migrations.AlterField( + model_name='confirmedemail', + name='photo', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='emails', to='ivataraccount.Photo'), + ), + migrations.AlterField( + model_name='confirmedopenid', + name='photo', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='openids', to='ivataraccount.Photo'), + ), + ] From e7d80d0b571b52c5286c5384802633c2e631805a Mon Sep 17 00:00:00 2001 From: Oliver Falk Date: Wed, 27 Jun 2018 09:35:17 +0200 Subject: [PATCH 4/9] Typo --- ivatar/ivataraccount/models.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ivatar/ivataraccount/models.py b/ivatar/ivataraccount/models.py index b73cc2f..7ff69eb 100644 --- a/ivatar/ivataraccount/models.py +++ b/ivatar/ivataraccount/models.py @@ -171,7 +171,7 @@ class Photo(BaseAccountModel): email.save() if openid: - # Explicitely asked + # Explicitly asked openid.photo = self openid.save() From 20a51602d91d090af6e1a2396174521187f03553 Mon Sep 17 00:00:00 2001 From: Oliver Falk Date: Wed, 27 Jun 2018 09:36:02 +0200 Subject: [PATCH 5/9] This is just to be _very_ safe, during testing, this can actually not happen at all and is therefore untestable --- ivatar/ivataraccount/migrations/0007_auto_20180627_0624.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ivatar/ivataraccount/migrations/0007_auto_20180627_0624.py b/ivatar/ivataraccount/migrations/0007_auto_20180627_0624.py index 97b3509..9a4d4ee 100644 --- a/ivatar/ivataraccount/migrations/0007_auto_20180627_0624.py +++ b/ivatar/ivataraccount/migrations/0007_auto_20180627_0624.py @@ -10,7 +10,7 @@ def add_sha256(apps, schema_editor): ''' ConfirmedEmail = apps.get_model('ivataraccount', 'ConfirmedEmail') for mail in ConfirmedEmail.objects.filter(digest_sha256=None): - mail.save() + mail.save() # pragma: no cover class Migration(migrations.Migration): From 12f80ac721f3d2c6adf9576d4168bee4ae045e1a Mon Sep 17 00:00:00 2001 From: Oliver Falk Date: Wed, 27 Jun 2018 09:36:32 +0200 Subject: [PATCH 6/9] No coverage here --- config.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/config.py b/config.py index 45ac71b..324a4e0 100644 --- a/config.py +++ b/config.py @@ -86,11 +86,11 @@ BOOTSTRAP4 = { } if not 'test' in sys.argv and not 'collectstatic' in sys.argv: - ANYMAIL = { + ANYMAIL = { # pragma: no cover 'MAILGUN_API_KEY': os.environ['IVATAR_MAILGUN_API_KEY'], 'MAILGUN_SENDER_DOMAIN': os.environ['IVATAR_MAILGUN_SENDER_DOMAIN'], } - EMAIL_BACKEND = 'anymail.backends.mailgun.EmailBackend' + EMAIL_BACKEND = 'anymail.backends.mailgun.EmailBackend' # pragma: no cover DEFAULT_FROM_EMAIL = 'ivatar@linux-kernel.at' try: @@ -98,13 +98,13 @@ try: except Exception: # pragma: no cover DATABASES = [] # pragma: no cover if not 'default' in DATABASES: - DATABASES['default'] = { + DATABASES['default'] = { # pragma: no cover 'ENGINE': 'django.db.backends.sqlite3', 'NAME': os.path.join(BASE_DIR, 'db.sqlite3'), } if 'MYSQL_DATABASE' in os.environ: - DATABASES['default'] = { + DATABASES['default'] = { # pragma: no cover 'ENGINE': 'django.db.backends.mysql', 'NAME': os.environ['MYSQL_DATABASE'], 'USER': os.environ['MYSQL_USER'], From 9f588b9221a6825bd11ec49b122c996af235c86b Mon Sep 17 00:00:00 2001 From: Oliver Falk Date: Wed, 27 Jun 2018 12:10:00 +0200 Subject: [PATCH 7/9] Docstring where pylint wants 'em, Ignore too many lines (for the moment at least), reorder module imports to make pylint happier, lots of pylint related adaptions and introduce test for CropPhotoView --- ivatar/ivataraccount/test_views.py | 232 +++++++++++++++++++++-------- 1 file changed, 167 insertions(+), 65 deletions(-) diff --git a/ivatar/ivataraccount/test_views.py b/ivatar/ivataraccount/test_views.py index 39d2009..5f1d133 100644 --- a/ivatar/ivataraccount/test_views.py +++ b/ivatar/ivataraccount/test_views.py @@ -1,26 +1,37 @@ -from django.test import TestCase -from django.test import Client -from django.urls import reverse - -from libravatar import libravatar_url +''' +Test our views in ivatar.ivataraccount.views and ivatar.views +''' +# pylint: disable=too-many-lines from urllib.parse import urlsplit - +from io import BytesIO import io import os import django +from django.test import TestCase +from django.test import Client +from django.urls import reverse +from django.contrib.auth.models import User +from django.contrib.auth import authenticate + +from libravatar import libravatar_url + +from PIL import Image + os.environ['DJANGO_SETTINGS_MODULE'] = 'ivatar.settings' django.setup() -from ivatar import settings # noqa -from ivatar.ivataraccount.forms import MAX_NUM_UNCONFIRMED_EMAILS_DEFAULT # noqa - -from django.contrib.auth.models import User # noqa -from django.contrib.auth import authenticate # noqa -from ivatar.utils import random_string # noqa -from ivatar.ivataraccount.models import Photo, ConfirmedOpenId # noqa +# pylint: disable=wrong-import-position +from ivatar import settings +from ivatar.ivataraccount.forms import MAX_NUM_UNCONFIRMED_EMAILS_DEFAULT +from ivatar.ivataraccount.models import Photo, ConfirmedOpenId +from ivatar.utils import random_string +# pylint: enable=wrong-import-position -class Tester(TestCase): +class Tester(TestCase): # pylint: disable=too-many-public-methods + ''' + Main test class + ''' client = Client() user = None username = random_string() @@ -170,7 +181,7 @@ class Tester(TestCase): self.user.confirmedemail_set.count(), 1, 'there must not be more or less than ONE (1) confirmed address!') - def test_confirm_email_w_invalid_auth_key(self): + def test_confirm_email_w_invalid_auth_key(self): # pylint: disable=invalid-name ''' Test confirmation with invalid auth key ''' @@ -193,7 +204,7 @@ class Tester(TestCase): 'Verification key incorrect', 'Confirm w/o verification key does not produce error message?') - def test_confirm_email_w_inexisting_auth_key(self): + def test_confirm_email_w_inexisting_auth_key(self): # pylint: disable=invalid-name ''' Test confirmation with inexisting auth key ''' @@ -246,7 +257,7 @@ class Tester(TestCase): 'Address removed', 'Removing confirmed mail does not work?') - def test_remove_not_existing_confirmed_email(self): + def test_remove_not_existing_confirmed_email(self): # pylint: disable=invalid-name ''' Try removing confirmed mail that doesn't exist ''' @@ -310,7 +321,8 @@ class Tester(TestCase): url = reverse( 'import_photo', args=[self.user.confirmedemail_set.first().id]) - response = self.client.post(url, { + response = self.client.post( + url, { 'photo_Gravatar': 1, }, follow=True @@ -340,7 +352,7 @@ class Tester(TestCase): self.assertEqual(response.status_code, 200, 'cannot fetch photo?') # Probably not the best way to access the content type self.assertEqual( - response._headers['content-type'][1], + response['Content-Type'], 'image/jpg', 'Content type wrong!?') @@ -428,10 +440,13 @@ class Tester(TestCase): }, follow=True ) - self.assertFormError(response, 'form', 'email', + self.assertFormError( + response, + 'form', + 'email', 'Address already added, currently unconfirmed') - def test_add_already_confirmed_email(self): + def test_add_already_confirmed_email(self): # pylint: disable=invalid-name ''' Request adding mail address that is already confirmed (by someone) ''' @@ -445,10 +460,13 @@ class Tester(TestCase): }, follow=True, ) - self.assertFormError(response, 'form', 'email', + self.assertFormError( + response, + 'form', + 'email', 'Address already confirmed (by someone else)') - def test_remove_unconfirmed_non_existing_email(self): + def test_remove_unconfirmed_non_existing_email(self): # pylint: disable=invalid-name ''' Remove unconfirmed email that doesn't exist ''' @@ -464,15 +482,19 @@ class Tester(TestCase): 'Address does not exist', 'Removing address that does not\ exist, should return error message!') - def test_upload_image(self, test_only_one=True): + def test_upload_image(self, test_only_one=True): # pylint: disable=inconsistent-return-statements ''' Test uploading image ''' self.login() url = reverse('upload_photo') # rb => Read binary - with open(os.path.join( - settings.STATIC_ROOT, 'img', 'deadbeef.png'), 'rb') as photo: + with open( + os.path.join( + settings.STATIC_ROOT, + 'img', + 'deadbeef.png'), + 'rb') as photo: response = self.client.post(url, { 'photo': photo, 'not_porn': True, @@ -542,15 +564,19 @@ class Tester(TestCase): 'Invalid Format', 'Invalid img data should return error message!') - def test_upload_invalid_image_format(self): + def test_upload_invalid_image_format(self): # pylint: disable=invalid-name ''' Test if invalid format is correctly detected ''' self.login() url = reverse('upload_photo') # rb => Read binary - with open(os.path.join( - settings.STATIC_ROOT, 'img', 'mm.svg'), 'rb') as photo: + with open( + os.path.join( + settings.STATIC_ROOT, + 'img', + 'mm.svg'), + 'rb') as photo: response = self.client.post(url, { 'photo': photo, 'not_porn': True, @@ -568,10 +594,12 @@ class Tester(TestCase): self.login() url = reverse('upload_photo') # rb => Read binary - with open(os.path.join( + with open( + os.path.join( settings.STATIC_ROOT, 'img', - 'broken.gif'), 'rb') as photo: + 'broken.gif'), + 'rb') as photo: response = self.client.post(url, { 'photo': photo, 'not_porn': True, @@ -585,17 +613,19 @@ class Tester(TestCase): self.user.photo_set.first().format, 'gif', 'Format must be gif, since we uploaded a GIF!') - def test_upload_unsupported_tif_image(self): + def test_upload_unsupported_tif_image(self): # pylint: disable=invalid-name ''' Test if unsupported format is correctly detected ''' self.login() url = reverse('upload_photo') # rb => Read binary - with open(os.path.join( + with open( + os.path.join( settings.STATIC_ROOT, 'img', - 'hackergotchi_test.tif'), 'rb') as photo: + 'hackergotchi_test.tif'), + 'rb') as photo: response = self.client.post(url, { 'photo': photo, 'not_porn': True, @@ -606,13 +636,19 @@ class Tester(TestCase): 'Invalid Format', 'Invalid img data should return error message!') - def test_automatic_photo_assign_to_confirmed_mail(self): + def test_automatic_photo_assign_to_confirmed_mail(self): # pylint: disable=invalid-name + ''' + Test if automatic assignment of photo works + ''' self.test_upload_image() self.test_confirm_email() confirmed = self.user.confirmedemail_set.first() self.assertEqual(confirmed.photo, self.user.photo_set.first()) def test_assign_photo_to_email(self): + ''' + Test assigning photo to mail address + ''' self.test_confirm_email() self.test_upload_image() self.assertIsNone(self.user.confirmedemail_set.first().photo) @@ -632,7 +668,10 @@ class Tester(TestCase): self.user.confirmedemail_set.first().photo, self.user.photo_set.first()) - def test_assign_photo_to_email_wo_photo_for_testing_template(self): + def test_assign_photo_to_email_wo_photo_for_testing_template(self): # pylint: disable=invalid-name + ''' + Test assign photo template + ''' self.test_confirm_email() url = reverse( 'assign_photo_email', @@ -641,7 +680,10 @@ class Tester(TestCase): response = self.client.get(url) self.assertEqual(response.status_code, 200, 'cannot fetch page?') - def test_assign_invalid_photo_id_to_email(self): + def test_assign_invalid_photo_id_to_email(self): # pylint: disable=invalid-name + ''' + Test if assigning an invalid photo id returns the correct error message + ''' self.test_confirm_email() self.test_upload_image() self.assertIsNone(self.user.confirmedemail_set.first().photo) @@ -659,7 +701,10 @@ class Tester(TestCase): 'Photo does not exist', 'Assign non existing photo, does not return error message?') - def test_post_to_assign_photo_without_photo_id(self): + def test_post_to_assign_photo_without_photo_id(self): # pylint: disable=invalid-name + ''' + Test if assigning photo without id returns the correct error message + ''' self.test_confirm_email() self.test_upload_image() self.assertIsNone(self.user.confirmedemail_set.first().photo) @@ -675,7 +720,11 @@ class Tester(TestCase): 'Invalid request [photo_id] missing', 'Assign non existing photo, does not return error message?') - def test_assign_photo_to_inexisting_mail(self): + def test_assign_photo_to_inexisting_mail(self): # pylint: disable=invalid-name + ''' + Test if assigning photo to mail address that doesn't exist returns + the correct error message + ''' self.test_upload_image() url = reverse('assign_photo_email', args=[1234]) response = self.client.post(url, { @@ -689,7 +738,11 @@ class Tester(TestCase): 'Invalid request', 'Assign non existing photo, does not return error message?') - def test_import_photo_with_inexisting_email(self): + def test_import_photo_with_inexisting_email(self): # pylint: disable=invalid-name + ''' + Test if import with inexisting mail address returns + the correct error message + ''' self.login() url = reverse('import_photo', args=[1234]) response = self.client.post(url, {}, follow=True) @@ -703,6 +756,10 @@ class Tester(TestCase): does not return error message?') def test_import_nothing(self): + ''' + Test if importing nothing causes the correct + error message to be returned + ''' self.test_confirm_email() url = reverse( 'import_photo', @@ -732,7 +789,6 @@ class Tester(TestCase): response = self.client.post( reverse('add_openid'), { - # Whohu, static... :-[ 'openid': self.openid, }, ) @@ -762,7 +818,6 @@ class Tester(TestCase): response = self.client.post( reverse('add_openid'), { - # Whohu, static... :-[ 'openid': self.openid, }, ) @@ -770,7 +825,6 @@ class Tester(TestCase): response = self.client.post( reverse('add_openid'), { - # Whohu, static... :-[ 'openid': self.openid, }, follow=True, @@ -779,8 +833,11 @@ class Tester(TestCase): self.user.unconfirmedopenid_set.count(), 1, 'There must only be one unconfirmed ID!') - self.assertFormError(response, 'form', 'openid', - 'OpenID already added, but not confirmed yet!') + self.assertFormError( + response, + 'form', + 'openid', + 'OpenID already added, but not confirmed yet!') # Manual confirm, since testing is _really_ hard! unconfirmed = self.user.unconfirmedopenid_set.first() @@ -794,16 +851,21 @@ class Tester(TestCase): # Try adding it again - although already confirmed response = self.client.post( reverse('add_openid'), { - # Whohu, static... :-[ 'openid': self.openid, }, follow=True, ) - self.assertFormError(response, 'form', 'openid', - 'OpenID already added and confirmed!') + self.assertFormError( + response, + 'form', + 'openid', + 'OpenID already added and confirmed!') def test_assign_photo_to_openid(self): + ''' + Test assignment of photo to openid + ''' self.test_add_openid() self.test_upload_image() self.assertIsNone(self.user.confirmedopenid_set.first().photo) @@ -823,7 +885,10 @@ class Tester(TestCase): self.user.confirmedopenid_set.first().photo, self.user.photo_set.first()) - def test_assign_photo_to_openid_wo_photo_for_testing_template(self): + def test_assign_photo_to_openid_wo_photo_for_testing_template(self): # pylint: disable=invalid-name + ''' + Test openid/photo assignment template + ''' self.test_add_openid() url = reverse( 'assign_photo_openid', @@ -831,7 +896,11 @@ class Tester(TestCase): response = self.client.get(url) self.assertEqual(response.status_code, 200, 'cannot fetch page?') - def test_assign_invalid_photo_id_to_openid(self): + def test_assign_invalid_photo_id_to_openid(self): # pylint: disable=invalid-name + ''' + Test assigning invalid photo to openid returns + the correct error message + ''' self.test_add_openid() self.assertIsNone(self.user.confirmedopenid_set.first().photo) url = reverse( @@ -848,7 +917,11 @@ class Tester(TestCase): 'Photo does not exist', 'Assign non existing photo, does not return error message?') - def test_post_to_assign_photo_openid_without_photo_id(self): + def test_post_to_assign_photo_openid_without_photo_id(self): # pylint: disable=invalid-name + ''' + Test POST assign photo to openid without photo id + returns the correct error message + ''' self.test_add_openid() self.test_upload_image() self.assertIsNone(self.user.confirmedopenid_set.first().photo) @@ -864,7 +937,11 @@ class Tester(TestCase): 'Invalid request [photo_id] missing', 'Assign non existing photo, does not return error message?') - def test_assign_photo_to_openid_inexisting_openid(self): + def test_assign_photo_to_openid_inexisting_openid(self): # pylint: disable=invalid-name + ''' + Test assigning photo to openid that doesn't exist + returns the correct error message. + ''' self.test_upload_image() url = reverse('assign_photo_openid', args=[1234]) response = self.client.post(url, { @@ -878,7 +955,7 @@ class Tester(TestCase): 'Invalid request', 'Assign non existing photo, does not return error message?') - def test_remove_confirmed_openid(self): + def test_remove_confirmed_openid(self): # pylint: disable=invalid-name ''' Remove confirmed openid ''' @@ -896,7 +973,7 @@ class Tester(TestCase): 'ID removed', 'Removing confirmed openid does not work?') - def test_remove_not_existing_confirmed_openid(self): + def test_remove_not_existing_confirmed_openid(self): # pylint: disable=invalid-name ''' Try removing confirmed openid that doesn't exist ''' @@ -931,7 +1008,7 @@ class Tester(TestCase): 'ID removed', 'Removing unconfirmed mail does not work?') - def test_remove_unconfirmed_inexisting_openid(self): + def test_remove_unconfirmed_inexisting_openid(self): # pylint: disable=invalid-name ''' Remove unconfirmed openid that doesn't exist ''' @@ -983,14 +1060,16 @@ class Tester(TestCase): self.user.photo_set.first(), 'set_photo did not work!?') - def test_avatar_url_mail(self): + def test_avatar_url_mail(self, do_upload_and_confirm=True): ''' Test fetching avatar via mail ''' - self.test_upload_image() - self.test_confirm_email() - urlobj = urlsplit(libravatar_url( - email=self.user.confirmedemail_set.first().email) + if do_upload_and_confirm: + self.test_upload_image() + self.test_confirm_email() + urlobj = urlsplit( + libravatar_url( + email=self.user.confirmedemail_set.first().email) ) url = urlobj.path response = self.client.get(url, follow=True) @@ -1008,8 +1087,9 @@ class Tester(TestCase): Test fetching avatar via openid ''' self.test_assign_photo_to_openid() - urlobj = urlsplit(libravatar_url( - openid=self.user.confirmedopenid_set.first().openid) + urlobj = urlsplit( + libravatar_url( + openid=self.user.confirmedopenid_set.first().openid) ) url = urlobj.path response = self.client.get(url, follow=True) @@ -1022,14 +1102,15 @@ class Tester(TestCase): self.user.photo_set.first().data, 'Why is this not the same data?') - def test_avatar_url_inexisting_mail_digest(self): + def test_avatar_url_inexisting_mail_digest(self): # pylint: disable=invalid-name ''' Test fetching avatar via inexisting mail digest ''' self.test_upload_image() self.test_confirm_email() - urlobj = urlsplit(libravatar_url( - email=self.user.confirmedemail_set.first().email) + urlobj = urlsplit( + libravatar_url( + email=self.user.confirmedemail_set.first().email) ) # Simply delete it, then it digest is 'correct', but # the hash is no longer there @@ -1037,3 +1118,24 @@ class Tester(TestCase): url = urlobj.path self.assertRaises(Exception, lambda: self.client.get(url, follow=True)) + + def test_crop_photo(self): + ''' + Test cropping photo + ''' + self.test_upload_image() + self.test_confirm_email() + url = reverse('crop_photo', args=[self.user.photo_set.first().pk]) + response = self.client.post(url, { + 'x': 10, + 'y': 10, + 'w': 20, + 'h': 20, + }, follow=True) + self.assertEqual( + response.status_code, + 200, + 'unable to crop?') + self.test_avatar_url_mail(do_upload_and_confirm=False) + img = Image.open(BytesIO(self.user.photo_set.first().data)) + self.assertEqual(img.size, (20, 20), 'cropped to 20x20, but resulting image isn\'t 20x20!?') From a10145c25b02dc408d61ebefec6544f9c7db816c Mon Sep 17 00:00:00 2001 From: Oliver Falk Date: Mon, 2 Jul 2018 14:28:42 +0200 Subject: [PATCH 8/9] Add max photo size, in order to use that variable in the template --- ivatar/context_processors.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ivatar/context_processors.py b/ivatar/context_processors.py index d9bcdb0..823188d 100644 --- a/ivatar/context_processors.py +++ b/ivatar/context_processors.py @@ -3,8 +3,7 @@ Default: useful variables for the base page templates. ''' from ipware import get_client_ip -from ivatar.settings import IVATAR_VERSION, SITE_NAME - +from ivatar.settings import IVATAR_VERSION, SITE_NAME, MAX_PHOTO_SIZE def basepage(request): ''' @@ -20,4 +19,5 @@ def basepage(request): context['ivatar_version'] = IVATAR_VERSION context['site_name'] = SITE_NAME context['site_url'] = request.build_absolute_uri('/')[:-1] + context['max_file_size'] = MAX_PHOTO_SIZE return context From 613e986290641281f27006c018d79ddb1499c2cf Mon Sep 17 00:00:00 2001 From: Oliver Falk Date: Tue, 3 Jul 2018 07:14:49 +0200 Subject: [PATCH 9/9] Merge in stashed changes --- ivatar/views.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ivatar/views.py b/ivatar/views.py index dba0573..dea22d4 100644 --- a/ivatar/views.py +++ b/ivatar/views.py @@ -22,7 +22,7 @@ class AvatarImageView(TemplateView): # Fetch by digest from mail pass elif len(kwargs['digest']) == 64: - if ConfirmedOpenId.objects.filter(digest=kwargs['digest']).count(): + if ConfirmedOpenId.objects.filter(digest=kwargs['digest']).count(): # pylint: disable=no-member # Fetch by digest from OpenID model = ConfirmedOpenId else: # pragma: no cover