Projet

Général

Profil

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

Paul Marillonnet, 19 septembre 2018 15:19

Télécharger (28,9 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             |  29 +++
 src/authentic2/forms/widgets.py               |  22 ++-
 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     |  20 +++
 src/authentic2/urls.py                        |   5 +
 src/authentic2/utils.py                       |  63 +++++++
 tests/cityscape.png                           | Bin 0 -> 508 bytes
 tests/conftest.py                             |  19 ++
 tests/garden.png                              | Bin 0 -> 506 bytes
 tests/test_attribute_kinds.py                 | 168 ++++++++++++++++++
 tests/test_manager.py                         |  23 +--
 tests/test_profile.py                         |  16 +-
 tox.ini                                       |   2 +
 23 files changed, 401 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/cityscape.png
 create mode 100644 tests/garden.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="", definition='Width x Height image dimensions in account management page.'),
180
    A2_ATTRIBUTE_KIND_IMAGE_CROPPING=Setting(default="", definition='Image cropping in account management page.'),
181
    A2_ATTRIBUTE_KIND_IMAGE_QUALITY=Setting(default=None, 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

  
......
25 26
    (pgettext_lazy('title', 'Mr'), pgettext_lazy('title', 'Mr')),
26 27
)
27 28

  
29
DEFAULT_IMAGE_DIMENSIONS = "150x150"
30
DEFAULT_IMAGE_CROPPING = "center"
31
DEFAULT_IMAGE_QUALITY = 99
28 32

  
29 33
class BirthdateWidget(widgets.DateWidget):
30 34
    help_text = _('Format: yyyy-mm-dd')
......
49 53
def get_title_choices():
50 54
    return app_settings.A2_ATTRIBUTE_KIND_TITLE_CHOICES or DEFAULT_TITLE_CHOICES
51 55

  
56

  
57
def get_image_thumbnail_parameters():
58
    return (app_settings.A2_ATTRIBUTE_KIND_IMAGE_DIMENSIONS or DEFAULT_IMAGE_DIMENSIONS,
59
        app_settings.A2_ATTRIBUTE_KIND_IMAGE_CROPPING or DEFAULT_IMAGE_CROPPING,
60
        app_settings.A2_ATTRIBUTE_KIND_IMAGE_QUALITY or DEFAULT_IMAGE_QUALITY)
61

  
62

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

  
......
151 162
        'field_class': PhoneNumberField,
152 163
        'rest_framework_field_class': PhoneNumberDRFField,
153 164
    },
165
    {
166
        'label': _('image'),
167
        'name': 'image',
168
        'field_class': forms.ImageField,
169
        'kwargs': {
170
            'widget': widgets.AttributeImageInput,
171
        },
172
        'serialize': image_serialize,
173
        'serialize_eval_kwargs': {
174
            'owner_uuid': 'owner.uuid',
175
            'owner_pk': 'owner.pk',
176
            'attr_label': 'self.label',
177
        },
178
        'deserialize': image_deserialize,
179
        'rest_framework_field_kwargs': {
180
            'read_only': True,
181
            },
182
    },
154 183
]
155 184

  
156 185

  
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
    template_name = "authentic2/accounts_image.html"
254
    # Deprecated (django<=1.8 only):
255
    template_with_initial = (
256
        '%(initial_text)s: <br /> <img src="%(initial)s"/> <br />'
257
        '%(clear_template)s<br />%(input_text)s: %(input)s'
258
    )
259

  
260
    def is_initial(self, value):
261
        return bool(value)
262

  
263
    def get_template_substitution_values(self, value):
264
        subs_values = dict()
265
        subs_values.update({
266
            'initial': value,
267
        })
268
        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 ..attribute_kinds import get_image_thumbnail_parameters
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, crop, quality = get_image_thumbnail_parameters()
17
        return get_thumbnail(img_url, dimensions, crop=crop, quality=quality)
18
    except:
19
        logger.error("Couldn't generate thumbnail for image {}".format(
20
                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, owner_uuid, attr_label):
1081
    img_tmp_path = u'{label}/{uuid_short}/{uuid}_{name}'.format(
1082
            label=attr_label,
1083
            uuid_short=owner_uuid[0:4],
1084
            uuid=owner_uuid,
1085
            name=in_memory_image.name)
1086

  
1087
    img_media_path = default_storage.save(img_tmp_path, in_memory_image)
1088

  
1089
    return img_media_path
1090

  
1091

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

  
1095
    logger = logging.getLogger(__name__)
1096
    User = get_user_model()
1097

  
1098
    try:
1099
        owner = User.objects.get(pk=owner_pk)
1100
    except User.DoesNotExist:
1101
        logger.error("Primary key {} doesn't match with any user.".format(owner_pk))
1102
        return
1103

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

  
1112
    for value in values:
1113
        if value.content:
1114
            # Direct URI <-> file location correspondence
1115
            local_file = value.content.split(default_storage.base_url)[-1]
1116
            default_storage.delete(local_file)
1117
        value.delete()
1118

  
1119

  
1120
def image_serialize(image, owner_uuid, owner_pk, attr_label):
1121
    img_media_path = ''
1122
    if isinstance(image, basestring):
1123
        img_media_path = image
1124
    else:
1125
        # Discard previous user avatars
1126
        _delete_images_from_user(owner_pk, attr_label)
1127
        if image:
1128
            img_media_path = _store_image(image, owner_uuid, attr_label)
1129
    return img_media_path
1130

  
1131

  
1132
def image_deserialize(img_media_path):
1133
    from authentic2.middleware import StoreRequestMiddleware
1134

  
1135
    if img_media_path:
1136
        request = StoreRequestMiddleware().get_request()
1137
        img_uri = os.path.join(settings.MEDIA_URL, img_media_path)
1138
        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):
354
        return u'http://testserver/{}'.format(uri)
355

  
356
    request = RequestFactory()
357
    request.build_absolute_uri = lambda: 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

  
288
    Attribute.objects.create(name='cityscape_image', label='cityscape', kind='image',
289
                             asked_on_registration=True)
290
    qs = User.objects.filter(first_name='John')
291

  
292

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

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

  
310
    form = response.form
311
    form.set('cityscape_image', Upload('tests/cityscape.png'))
312
    form.set('password1', '12345abcdA')
313
    form.set('password2', '12345abcdA')
314
    response = form.submit()
315

  
316
    john = qs.get()
317
    monkeypatch.setattr(StoreRequestMiddleware, 'get_request', lambda cls: monkeyrequest)
318
    assert john.uuid in john.attributes.cityscape_image
319
    monkeypatch.undo()
320

  
321
    app.authorization = ('Basic', (admin.username, admin.username))
322

  
323
    resp = app.get('/api/users/?first_name=John&last_name=Doe')
324
    assert john.uuid in resp.json_body['results'][0]['cityscape_image']
325

  
326
    qs.delete()
327

  
328
    response = app.get(url)
329
    form = response.form
330
    form.set('first_name', 'John')
331
    form.set('last_name', 'Doe')
332
    form.set('cityscape_image', None)
333
    form.set('password1', '12345abcdA')
334
    form.set('password2', '12345abcdA')
335
    response = form.submit().follow()
336
    assert qs.get().attributes.cityscape_image == None
337
    qs.delete()
338

  
339
def test_images_delete_on_form_field_clearance(db, app, admin, mailoutbox):
340
    from django.core.files.storage import default_storage
341
    from webtest import Upload
342

  
343
    Attribute.objects.create(
344
            name='cityscape_image', label='cityscape', kind='image',
345
            asked_on_registration=False, required=False,
346
            user_visible=True, user_editable=True)
347
    Attribute.objects.create(
348
            name='garden_image', label='garden', kind='image',
349
            asked_on_registration=False, required=False,
350
            user_visible=True, user_editable=True)
351

  
352
    qs = User.objects.filter(first_name='John')
353

  
354
    response = app.get('/accounts/register/')
355
    form = response.form
356
    form.set('email', 'john.doe@example.com')
357
    response = form.submit().follow()
358
    assert 'john.doe@example.com' in response
359
    url = get_link_from_mail(mailoutbox[0])
360
    response = app.get(url)
361

  
362
    form = response.form
363
    form.set('first_name', 'John')
364
    form.set('last_name', 'Doe')
365
    form.set('password1', '12345abcdA')
366
    form.set('password2', '12345abcdA')
367
    response = form.submit()
368

  
369
    john = qs.get()
370
    assert john
371
    img_path1 = 'cityscape/{uuid_short}/{uuid}_cityscape.png'.format(
372
            uuid_short=john.uuid[0:4],
373
            uuid=john.uuid)
374
    img_path2 = 'garden/{uuid_short}/{uuid}_garden.png'.format(
375
            uuid_short=john.uuid[0:4],
376
            uuid=john.uuid)
377

  
378
    assert not default_storage.exists(img_path1)
379
    assert not default_storage.exists(img_path2)
380

  
381
    response = app.get('/accounts/edit/')
382
    form = response.form
383
    form.set('edit-profile-cityscape_image', Upload('tests/cityscape.png'))
384
    response = form.submit()
385

  
386
    assert default_storage.exists(img_path1)
387
    assert not default_storage.exists(img_path2)
388

  
389
    response = app.get('/accounts/edit/')
390
    form = response.form
391
    form.set('edit-profile-garden_image', Upload('tests/garden.png'))
392
    response = form.submit()
393

  
394
    assert default_storage.exists(img_path1)
395
    assert default_storage.exists(img_path2)
396

  
397
    response = app.get('/accounts/edit/')
398
    form = response.form
399
    form.set('edit-profile-cityscape_image-clear', True)
400
    response = form.submit()
401

  
402
    assert not default_storage.exists(img_path1)
403
    assert default_storage.exists(img_path2)
404

  
405
    response = app.get('/accounts/edit/')
406
    form = response.form
407
    form.set('edit-profile-garden_image-clear', True)
408
    response = form.submit()
409

  
410
    assert not default_storage.exists(img_path1)
411
    assert not default_storage.exists(img_path2)
412

  
413

  
414
def test_images_account_registration(db, app, admin, mailoutbox, monkeypatch, monkeyrequest):
415
    from webtest import Upload
416
    from authentic2.middleware import StoreRequestMiddleware
417
    from django.test import RequestFactory
418

  
419
    Attribute.objects.create(name='cityscape_image', label='cityscape', kind='image',
420
                             asked_on_registration=True)
421
    Attribute.objects.create(name='garden_image', label='garden', kind='image',
422
                             asked_on_registration=True)
423
    qs = User.objects.filter(first_name='John')
424

  
425
    response = app.get('/accounts/register/')
426
    form = response.form
427
    form.set('email', 'john.doe@example.com')
428
    response = form.submit().follow()
429
    assert 'john.doe@example.com' in response
430
    url = get_link_from_mail(mailoutbox[0])
431
    response = app.get(url)
432

  
433
    form = response.form
434
    assert form.get('cityscape_image')
435
    assert form.get('garden_image')
436
    form.set('first_name', 'John')
437
    form.set('last_name', 'Doe')
438
    form.set('cityscape_image', Upload('tests/cityscape.png'))
439
    form.set('garden_image', Upload('tests/garden.png'))
440
    form.set('password1', '12345abcdA')
441
    form.set('password2', '12345abcdA')
442
    response = form.submit()
443

  
444
    john = qs.get()
445
    monkeypatch.setattr(StoreRequestMiddleware, 'get_request', lambda cls: monkeyrequest)
446
    assert john.attributes.cityscape_image
447
    assert john.attributes.garden_image
448
    monkeypatch.undo()
449
    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
-