Projet

Général

Profil

0001-support-avatar-picture-in-user-profile-26022.patch

Paul Marillonnet, 01 octobre 2018 17:29

Télécharger (29,1 ko)

Voir les différences:

Subject: [PATCH] support avatar picture in user profile (#26022)

 debian-wheezy/control                         |   3 +-
 debian/control                                |   3 +-
 setup.py                                      |   2 +
 src/authentic2/app_settings.py                |   3 +
 src/authentic2/attribute_kinds.py             |  18 ++
 src/authentic2/forms/widgets.py               |  25 ++-
 src/authentic2/models.py                      |  19 +-
 src/authentic2/settings.py                    |   3 +
 .../templates/authentic2/accounts.html        |  20 +-
 .../templates/authentic2/accounts_edit.html   |   3 +-
 .../templates/authentic2/accounts_image.html  |   6 +
 .../registration/registration_form.html       |   3 +-
 src/authentic2/templatetags/__init__.py       |   0
 src/authentic2/templatetags/authentic2.py     |  22 +++
 src/authentic2/urls.py                        |   5 +
 src/authentic2/utils.py                       |  65 +++++++
 tests/conftest.py                             |  19 ++
 tests/test_attribute_kinds.py                 | 181 ++++++++++++++++++
 tests/test_manager.py                         |  23 +--
 tests/test_profile.py                         |  16 +-
 "tests/une deuxi\303\250me image.png"         | Bin 0 -> 506 bytes
 "tests/une premi\303\250re image.png"         | Bin 0 -> 508 bytes
 tox.ini                                       |   2 +
 23 files changed, 410 insertions(+), 31 deletions(-)
 create mode 100644 src/authentic2/templates/authentic2/accounts_image.html
 create mode 100644 src/authentic2/templatetags/__init__.py
 create mode 100644 src/authentic2/templatetags/authentic2.py
 create mode 100644 "tests/une deuxi\303\250me image.png"
 create mode 100644 "tests/une premi\303\250re image.png"
debian-wheezy/control
25 25
    python-markdown (>= 2.1),
26 26
    python-ldap (>= 2.4),
27 27
    python-six (>= 1.0),
28
    python-django-filters (>= 1)
28
    python-django-filters (>= 1),
29
    python-sorl-thumbnail
29 30
Provides: ${python:Provides}
30 31
Recommends: python-ldap
31 32
Suggests: python-raven
debian/control
28 28
    python-jwcrypto (>= 0.3.1),
29 29
    python-cryptography (>= 1.3.4),
30 30
    python-django-filters (>= 1),
31
    python-django-filters (<< 2)
31
    python-django-filters (<< 2),
32
    python-sorl-thumbnail
32 33
Provides: ${python:Provides}
33 34
Recommends: python-ldap
34 35
Suggests: python-raven
setup.py
131 131
          'XStatic-jQuery',
132 132
          'XStatic-jquery-ui<1.12',
133 133
          'xstatic-select2',
134
          'sorl-thumbnail',
135
          'pillow',
134 136
      ],
135 137
      zip_safe=False,
136 138
      classifiers=[
src/authentic2/app_settings.py
176 176
            'next try after a login failure'),
177 177
    A2_VERIFY_SSL=Setting(default=True, definition='Verify SSL certificate in HTTP requests'),
178 178
    A2_ATTRIBUTE_KIND_TITLE_CHOICES=Setting(default=(), definition='Choices for the title attribute kind'),
179
    A2_ATTRIBUTE_KIND_IMAGE_DIMENSIONS=Setting(default="150x150", definition='Width x Height image dimensions in account management page.'),
180
    A2_ATTRIBUTE_KIND_IMAGE_CROPPING=Setting(default="center", definition='Image cropping in account management page.'),
181
    A2_ATTRIBUTE_KIND_IMAGE_QUALITY=Setting(default=99, definition='Image quality in account management page.'),
179 182
    A2_CORS_WHITELIST=Setting(default=(), definition='List of origin URL to whitelist, must be scheme://netloc[:port]'),
180 183
    A2_EMAIL_CHANGE_TOKEN_LIFETIME=Setting(default=7200, definition='Lifetime in seconds of the '
181 184
                                           'token sent to verify email adresses'),
src/authentic2/attribute_kinds.py
17 17
from .plugins import collect_from_plugins
18 18
from . import app_settings
19 19
from .forms import widgets
20
from .utils import image_serialize, image_deserialize
20 21

  
21 22
capfirst = allow_lazy(capfirst, unicode)
22 23

  
......
49 50
def get_title_choices():
50 51
    return app_settings.A2_ATTRIBUTE_KIND_TITLE_CHOICES or DEFAULT_TITLE_CHOICES
51 52

  
53

  
52 54
validate_phone_number = RegexValidator('^\+?\d{,20}$', message=_('Phone number can start with a + '
53 55
                                                                 'an must contain only digits.'))
54 56

  
......
151 153
        'field_class': PhoneNumberField,
152 154
        'rest_framework_field_class': PhoneNumberDRFField,
153 155
    },
156
    {
157
        'label': _('image'),
158
        'name': 'image',
159
        'field_class': forms.ImageField,
160
        'kwargs': {
161
            'widget': widgets.AttributeImageInput,
162
        },
163
        'serialize': image_serialize,
164
        'serialize_eval_kwargs': {
165
            'attr_label': 'self.label',
166
        },
167
        'deserialize': image_deserialize,
168
        'rest_framework_field_kwargs': {
169
            'read_only': True,
170
            },
171
    },
154 172
]
155 173

  
156 174

  
src/authentic2/forms/widgets.py
11 11
import re
12 12
import uuid
13 13

  
14
from django.forms.widgets import DateTimeInput, DateInput, TimeInput
14
from django.forms.widgets import DateTimeInput, DateInput, TimeInput, \
15
        ClearableFileInput
15 16
from django.forms.widgets import PasswordInput as BasePasswordInput
16 17
from django.utils.formats import get_language, get_format
17 18
from django.utils.safestring import mark_safe
......
246 247
                    json.dumps(_id),
247 248
                )
248 249
        return output
250

  
251

  
252
class AttributeImageInput(ClearableFileInput):
253
    import django
254

  
255
    if django.VERSION < (1, 9):
256
        template_with_initial = (
257
            '%(initial_text)s: <br /> <img src="%(initial)s"/> <br />'
258
            '%(clear_template)s<br />%(input_text)s: %(input)s'
259
        )
260
    else:
261
        template_name = "authentic2/accounts_image.html"
262

  
263
    def is_initial(self, value):
264
        return bool(value)
265

  
266
    def get_template_substitution_values(self, value):
267
        subs_values = dict()
268
        subs_values.update({
269
            'initial': value,
270
        })
271
        return subs_values
src/authentic2/models.py
1
import logging
1 2
import time
2 3
import urlparse
3 4
import uuid
......
203 204
                return kind['default']
204 205

  
205 206
    def set_value(self, owner, value, verified=False):
207
        logger = logging.getLogger(__name__)
206 208
        serialize = self.get_kind()['serialize']
207 209
        # setting to None is to delete
208 210
        if value is None:
......
225 227
                    av.verified = verified
226 228
                    av.save()
227 229
        else:
228
            content = serialize(value)
230
            kwargs = dict()
231
            for key, flat_value in self.get_kind().get('serialize_eval_kwargs', {}).items():
232
                try:
233
                    evalue = eval(flat_value)
234
                except NameError:
235
                    logger.error("Couldn't evaluate {} for attribute <{}: {}>".format(
236
                            flat_value,
237
                            self.get_kind()['kind'],
238
                            self.label))
239
                    continue
240
                kwargs.update({key: evalue})
241
            if kwargs:
242
                content = serialize(value, **kwargs)
243
            else:
244
                content = serialize(value)
245

  
229 246
            av, created = AttributeValue.objects.get_or_create(
230 247
                    content_type=ContentType.objects.get_for_model(owner),
231 248
                    object_id=owner.pk,
src/authentic2/settings.py
22 22
DEBUG = False
23 23
DEBUG_DB = False
24 24
MEDIA = 'media'
25
MEDIA_ROOT = 'media'
26
MEDIA_URL = '/media/'
25 27

  
26 28
# See https://docs.djangoproject.com/en/dev/ref/settings/#allowed-hosts
27 29
ALLOWED_HOSTS = []
......
132 134
    'xstatic.pkg.jquery',
133 135
    'xstatic.pkg.jquery_ui',
134 136
    'xstatic.pkg.select2',
137
    'sorl.thumbnail',
135 138
)
136 139

  
137 140
INSTALLED_APPS = tuple(plugins.register_plugins_installed_apps(INSTALLED_APPS))
src/authentic2/templates/authentic2/accounts.html
1 1
{% extends "authentic2/base-page.html" %}
2 2
{% load i18n %}
3
{% load authentic2 %}
3 4

  
4 5
{% block page-title %}
5 6
  {{ block.super }} - {{ view.title }}
......
18 19
          {% for attribute in attributes %}
19 20
            <dt>{{ attribute.attribute.label|capfirst }}&nbsp;:</dt>
20 21
            <dd>
21
              {% if attribute.values|length == 1 %}
22
                {{ attribute.values.0 }}
22
              {% if attribute.attribute.kind == 'image' %}
23
                  {% thumbnail attribute.values.0 as thumb_im %}
24
                  <img class="{{ attribute.attribute.name }}" src="{{ thumb_im.url }}">
23 25
              {% else %}
24
                <ul>
25
                  {% for value in attribute.values %}
26
                    <li>{{ value }}</li>
27
                  {% endfor %}
28
                </ul>
26
                {% if attribute.values|length == 1 %}
27
                  {{ attribute.values.0 }}
28
                {% else %}
29
                  <ul>
30
                    {% for value in attribute.values %}
31
                      <li>{{ value }}</li>
32
                    {% endfor %}
33
                  </ul>
34
                {% endif %}
29 35
              {% endif %}
30 36
            </dd>
31 37
          {% endfor %}
src/authentic2/templates/authentic2/accounts_edit.html
12 12
{% endblock %}
13 13

  
14 14
{% block content %}
15
  <form method="post">
15
  <form enctype="multipart/form-data" method="post">
16

  
16 17
    {% csrf_token %}
17 18
    {{ form.as_p }}
18 19
    {% if form.instance and form.instance.id %}
src/authentic2/templates/authentic2/accounts_image.html
1
{% if widget.is_initial %}{{ widget.initial_text }}: <img src="{{ widget.value }}"/><br />
2
{% if not widget.required %}
3
<input type="checkbox" name="{{ widget.checkbox_name }}" id="{{ widget.checkbox_id }}" />
4
<label for="{{ widget.checkbox_id }}">{{ widget.clear_checkbox_label }}</label>{% endif %}
5
{{ widget.input_text }}:{% endif %}
6
<input type="{{ widget.type }}" name="{{ widget.name }}"{% include "django/forms/widgets/attrs.html" %} />
src/authentic2/templates/registration/registration_form.html
15 15

  
16 16
<h2>{{ view.title }}</h2>
17 17

  
18
<form method="post">
18
<form enctype="multipart/form-data" method="post">
19

  
19 20
  {% csrf_token %}
20 21
  {{ form.as_p }}
21 22
  <button class="submit-button">{% trans 'Submit' %}</button>
src/authentic2/templatetags/authentic2.py
1
import logging
2

  
3
from django import template
4
from sorl.thumbnail import get_thumbnail
5
from .. import app_settings
6

  
7
register = template.Library()
8

  
9

  
10
@register.assignment_tag(takes_context=True)
11
def thumbnail(context, img_value):
12
    logger = logging.getLogger(__name__)
13

  
14
    try:
15
        img_url = context['request'].build_absolute_uri(img_value)
16
        dimensions = app_settings.A2_ATTRIBUTE_KIND_IMAGE_DIMENSIONS
17
        crop = app_settings.A2_ATTRIBUTE_KIND_IMAGE_CROPPING
18
        quality =  app_settings.A2_ATTRIBUTE_KIND_IMAGE_QUALITY
19
        return get_thumbnail(img_url, dimensions, crop=crop, quality=quality)
20
    except:
21
        logger.error("Couldn't generate thumbnail for image {}".format(
22
                img_value))
src/authentic2/urls.py
2 2
from django.conf import settings
3 3
from django.contrib import admin
4 4
from django.contrib.staticfiles.views import serve
5
from django.views.static import serve as media_serve
5 6

  
6 7
from . import app_settings, plugins, views
7 8

  
......
44 45
    urlpatterns += [
45 46
        url(r'^static/(?P<path>.*)$', serve)
46 47
    ]
48
    urlpatterns += [
49
        url(r'^media/(?P<path>.*)$', media_serve, {
50
        'document_root': settings.MEDIA_ROOT})
51
    ]
47 52

  
48 53
if settings.DEBUG and 'debug_toolbar' in settings.INSTALLED_APPS:
49 54
    import debug_toolbar
src/authentic2/utils.py
8 8
import uuid
9 9
import datetime
10 10
import copy
11
import os
11 12

  
12 13
from functools import wraps
13 14
from itertools import islice, chain, count
......
30 31
from django.template.loader import render_to_string, TemplateDoesNotExist
31 32
from django.core.mail import send_mail
32 33
from django.core import signing
34
from django.core.files.storage import default_storage
33 35
from django.core.urlresolvers import reverse, NoReverseMatch
34 36
from django.utils.formats import localize
35 37
from django.contrib import messages
......
1073 1075
        if ou_value is not None:
1074 1076
            return ou_value
1075 1077
    return default
1078

  
1079

  
1080
def _store_image(in_memory_image):
1081
    from hashlib import sha1
1082

  
1083
    h = sha1(in_memory_image.read()).hexdigest()
1084
    extension = in_memory_image.image.format
1085
    img_tmp_path = u'images/%s/%s.%s' % (h[:3], h[3:], extension)
1086
    img_media_path = default_storage.save(img_tmp_path, in_memory_image)
1087

  
1088
    return img_media_path
1089

  
1090

  
1091
def _delete_images_from_user(attr_label):
1092
    from .models import Attribute, AttributeValue
1093
    from .middleware import StoreRequestMiddleware
1094

  
1095
    logger = logging.getLogger(__name__)
1096
    User = get_user_model()
1097
    request = StoreRequestMiddleware.get_request()
1098

  
1099
    try:
1100
        user = request.user
1101
    except :
1102
        logger.error("Couldn't retrieve user for request {}.".format(request))
1103
        return
1104

  
1105
    try:
1106
        attr = Attribute.objects.get(label=attr_label)
1107
        all_values =  AttributeValue.objects.with_owner(user)
1108
        values = all_values.filter(attribute=attr)
1109
    except:
1110
        logger.error("Couldn't retrieve values for Attribute {}.".format(attr_label))
1111
        return
1112

  
1113
    for value in values:
1114
        if value.content:
1115
            default_storage.delete(value.content)
1116
        value.delete()
1117

  
1118

  
1119
def image_serialize(image, attr_label):
1120
    from urllib import unquote
1121

  
1122
    img_media_path = ''
1123
    if isinstance(image, basestring):
1124
        img_url = unquote(image).decode('utf8')
1125
        img_media_path = img_url.split(default_storage.base_url)[-1]
1126
    else:
1127
        # Discard previous user images
1128
        _delete_images_from_user(attr_label)
1129
        if image:
1130
            img_media_path = _store_image(image)
1131
    return img_media_path
1132

  
1133

  
1134
def image_deserialize(img_media_path):
1135
    from authentic2.middleware import StoreRequestMiddleware
1136

  
1137
    if img_media_path:
1138
        request = StoreRequestMiddleware().get_request()
1139
        img_uri = os.path.join(settings.MEDIA_URL, img_media_path)
1140
        return request.build_absolute_uri(img_uri)
tests/conftest.py
339 339
    activate('fr')
340 340
    yield
341 341
    deactivate()
342

  
343

  
344
@pytest.fixture(autouse=True)
345
def authentic_settings(settings, tmpdir):
346
    settings.MEDIA_ROOT = str(tmpdir)
347

  
348

  
349
@pytest.fixture
350
def monkeyrequest(monkeypatch):
351
    from django.test import RequestFactory
352

  
353
    def fake_absolute_uri(uri=None):
354
            return u'http://testserver/{}'.format(uri or u'')
355

  
356
    request = RequestFactory()
357
    request.build_absolute_uri = lambda x: None
358
    monkeypatch.setattr(request, 'build_absolute_uri', fake_absolute_uri)
359

  
360
    return request
tests/test_attribute_kinds.py
279 279
    app.post_json('/api/users/', params=payload)
280 280
    assert qs.get().attributes.phone_number == ''
281 281
    qs.delete()
282

  
283

  
284
def test_image(db, app, admin, mailoutbox, monkeypatch, monkeyrequest):
285
    from webtest import Upload
286
    from authentic2.middleware import StoreRequestMiddleware
287
    from hashlib import sha1
288

  
289
    Attribute.objects.create(name='cityscape_image', label='cityscape', kind='image',
290
                             asked_on_registration=True, required=False,
291
                             user_visible=True, user_editable=True)
292
    qs = User.objects.filter(first_name='John')
293

  
294

  
295
    response = app.get('/accounts/register/')
296
    form = response.form
297
    form.set('email', 'john.doe@example.com')
298
    response = form.submit().follow()
299
    assert 'john.doe@example.com' in response
300
    url = get_link_from_mail(mailoutbox[0])
301
    response = app.get(url)
302

  
303
    form = response.form
304
    form.set('first_name', 'John')
305
    form.set('last_name', 'Doe')
306
    form.set('cityscape_image', Upload('/dev/null'))
307
    form.set('password1', '12345abcdA')
308
    form.set('password2', '12345abcdA')
309
    response = form.submit()
310
    assert response.pyquery.find('.form-field-error #id_cityscape_image')
311

  
312
    form = response.form
313
    form.set('cityscape_image', Upload('tests/une première image.png'))
314
    form.set('password1', '12345abcdA')
315
    form.set('password2', '12345abcdA')
316
    response = form.submit()
317

  
318
    with open('tests/une première image.png') as f:
319
        john = qs.get()
320
        xdigest = sha1(f.read()).hexdigest()
321
        monkeypatch.setattr(StoreRequestMiddleware, 'get_request', lambda cls: monkeyrequest)
322
        assert xdigest[:3] in john.attributes.cityscape_image
323
        assert xdigest[3:] in john.attributes.cityscape_image
324
        monkeypatch.undo()
325

  
326
    app.authorization = ('Basic', (admin.username, admin.username))
327
    resp = app.get('/api/users/?first_name=John&last_name=Doe')
328

  
329
    with open('tests/une première image.png') as f:
330
        xdigest = sha1(f.read()).hexdigest()
331
        assert xdigest[:3] in resp.json_body['results'][0]['cityscape_image']
332
        assert xdigest[3:] in resp.json_body['results'][0]['cityscape_image']
333

  
334
    response = app.get('/accounts/edit/')
335
    form = response.form
336
    form.set('edit-profile-first_name', 'John')
337
    form.set('edit-profile-last_name', 'Doe')
338
    form.set('edit-profile-cityscape_image', None)
339
    response = form.submit()
340

  
341
    monkeypatch.setattr(StoreRequestMiddleware, 'get_request', lambda cls: monkeyrequest)
342
    assert qs.get().attributes.cityscape_image == None
343
    monkeypatch.undo()
344

  
345
    qs.delete()
346

  
347
def test_images_delete_on_form_field_clearance(db, app, admin, mailoutbox):
348
    from django.core.files.storage import default_storage
349
    from webtest import Upload
350
    from hashlib import sha1
351

  
352
    Attribute.objects.create(
353
            name='cityscape_image', label='cityscape', kind='image',
354
            asked_on_registration=False, required=False,
355
            user_visible=True, user_editable=True)
356
    Attribute.objects.create(
357
            name='garden_image', label='garden', kind='image',
358
            asked_on_registration=False, required=False,
359
            user_visible=True, user_editable=True)
360

  
361
    qs = User.objects.filter(first_name='John')
362

  
363
    response = app.get('/accounts/register/')
364
    form = response.form
365
    form.set('email', 'john.doe@example.com')
366
    response = form.submit().follow()
367
    assert 'john.doe@example.com' in response
368
    url = get_link_from_mail(mailoutbox[0])
369
    response = app.get(url)
370

  
371
    form = response.form
372
    form.set('first_name', 'John')
373
    form.set('last_name', 'Doe')
374
    form.set('password1', '12345abcdA')
375
    form.set('password2', '12345abcdA')
376
    response = form.submit()
377

  
378
    john = qs.get()
379
    assert john
380

  
381
    f = open('tests/une première image.png')
382
    h = sha1(f.read()).hexdigest()
383
    img_path1 = 'images/%s/%s.PNG' % (h[:3], h[3:])
384
    f.close()
385

  
386
    f =  open('tests/une deuxième image.png')
387
    h = sha1(f.read()).hexdigest()
388
    img_path2 = 'images/%s/%s.PNG' % (h[:3], h[3:])
389
    f.close()
390

  
391
    assert not default_storage.exists(img_path1)
392
    assert not default_storage.exists(img_path2)
393

  
394
    response = app.get('/accounts/edit/')
395
    form = response.form
396
    form.set('edit-profile-cityscape_image', Upload('tests/une première image.png'))
397
    response = form.submit()
398

  
399
    assert default_storage.exists(img_path1)
400
    assert not default_storage.exists(img_path2)
401

  
402
    response = app.get('/accounts/edit/')
403
    form = response.form
404
    form.set('edit-profile-garden_image', Upload('tests/une deuxième image.png'))
405
    response = form.submit()
406

  
407
    assert default_storage.exists(img_path1)
408
    assert default_storage.exists(img_path2)
409

  
410
    response = app.get('/accounts/edit/')
411
    form = response.form
412
    form.set('edit-profile-cityscape_image-clear', True)
413
    response = form.submit()
414

  
415
    assert not default_storage.exists(img_path1)
416
    assert default_storage.exists(img_path2)
417

  
418
    response = app.get('/accounts/edit/')
419
    form = response.form
420
    form.set('edit-profile-garden_image-clear', True)
421
    response = form.submit()
422

  
423
    assert not default_storage.exists(img_path1)
424
    assert not default_storage.exists(img_path2)
425

  
426

  
427
def test_images_account_registration(db, app, admin, mailoutbox, monkeypatch, monkeyrequest):
428
    from webtest import Upload
429
    from authentic2.middleware import StoreRequestMiddleware
430
    from django.test import RequestFactory
431

  
432
    Attribute.objects.create(name='cityscape_image', label='cityscape', kind='image',
433
                             asked_on_registration=True)
434
    Attribute.objects.create(name='garden_image', label='garden', kind='image',
435
                             asked_on_registration=True)
436
    qs = User.objects.filter(first_name='John')
437

  
438
    response = app.get('/accounts/register/')
439
    form = response.form
440
    form.set('email', 'john.doe@example.com')
441
    response = form.submit().follow()
442
    assert 'john.doe@example.com' in response
443
    url = get_link_from_mail(mailoutbox[0])
444
    response = app.get(url)
445

  
446
    form = response.form
447
    assert form.get('cityscape_image')
448
    assert form.get('garden_image')
449
    form.set('first_name', 'John')
450
    form.set('last_name', 'Doe')
451
    form.set('cityscape_image', Upload('tests/une première image.png'))
452
    form.set('garden_image', Upload('tests/une deuxième image.png'))
453
    form.set('password1', '12345abcdA')
454
    form.set('password2', '12345abcdA')
455
    response = form.submit()
456

  
457
    john = qs.get()
458
    monkeypatch.setattr(StoreRequestMiddleware, 'get_request', lambda cls: monkeyrequest)
459
    assert john.attributes.cityscape_image
460
    assert john.attributes.garden_image
461
    monkeypatch.undo()
462
    john.delete()
tests/test_manager.py
105 105
    resp = login(app, superuser,
106 106
                 reverse('a2-manager-user-detail', kwargs={'pk': simple_user.pk}))
107 107
    assert len(mail.outbox) == 0
108
    resp = resp.form.submit('password_reset')
109
    assert 'A mail was sent to' in resp
110
    assert len(mail.outbox) == 1
111
    url = get_link_from_mail(mail.outbox[0])
112
    relative_url = url.split('testserver')[1]
113
    resp = app.get('/logout/').maybe_follow()
114
    resp = app.get(relative_url, status=200)
115
    resp.form.set('new_password1', '1234==aA')
116
    resp.form.set('new_password2', '1234==aA')
117
    resp = resp.form.submit().follow()
118
    assert str(app.session['_auth_user_id']) == str(simple_user.pk)
108
    if resp.form.enctype == u'application/x-www-form-urlencoded':
109
        resp = resp.form.submit('password_reset')
110
        assert 'A mail was sent to' in resp
111
        assert len(mail.outbox) == 1
112
        url = get_link_from_mail(mail.outbox[0])
113
        relative_url = url.split('testserver')[1]
114
        resp = app.get('/logout/').maybe_follow()
115
        resp = app.get(relative_url, status=200)
116
        resp.form.set('new_password1', '1234==aA')
117
        resp.form.set('new_password2', '1234==aA')
118
        resp = resp.form.submit().follow()
119
        assert str(app.session['_auth_user_id']) == str(simple_user.pk)
119 120

  
120 121

  
121 122
def test_manager_user_detail_by_uuid(app, superuser, simple_user):
tests/test_profile.py
36 36
    assert attribute.get_value(simple_user) == '0123456789'
37 37

  
38 38
    resp = app.get(url, status=200)
39
    resp.form.set('edit-profile-phone', '9876543210')
40
    resp = resp.form.submit('cancel').follow()
41
    assert attribute.get_value(simple_user) == '0123456789'
39
    if resp.form.enctype == u'application/x-www-form-urlencoded':
40
        resp.form.set('edit-profile-phone', '9876543210')
41
        resp = resp.form.submit('cancel').follow()
42
        assert attribute.get_value(simple_user) == '0123456789'
42 43

  
43 44
    attribute.set_value(simple_user, '0123456789', verified=True)
44 45
    resp = app.get(url, status=200)
......
74 75
    assert attribute.get_value(simple_user) == '0123456789'
75 76

  
76 77
    resp = app.get(url + '?next=%s' % external_redirect_next_url, status=200)
77
    resp.form.set('edit-profile-phone', '1234')
78
    resp = resp.form.submit('cancel')
79
    assert_external_redirect(resp, reverse('account_management'))
80
    assert attribute.get_value(simple_user) == '0123456789'
78
    if resp.form.enctype == u'application/x-www-form-urlencoded':
79
        resp.form.set('edit-profile-phone', '1234')
80
        resp = resp.form.submit('cancel')
81
        assert_external_redirect(resp, reverse('account_management'))
82
        assert attribute.get_value(simple_user) == '0123456789'
81 83

  
82 84

  
83 85
def test_account_edit_scopes(app, simple_user):
tox.ini
47 47
  httmock
48 48
  pytz
49 49
  pytest-freezegun
50
  pillow
51
  sorl-thumbnail
50 52
commands =
51 53
  ./getlasso.sh
52 54
  authentic: py.test {env:FAST:} {env:REUSEDB:} {env:COVERAGE:} {posargs:tests/ --random}
53
-