Projet

Général

Profil

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

Paul Marillonnet, 05 septembre 2018 17:51

Télécharger (10 ko)

Voir les différences:

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

 src/authentic2/attribute_kinds.py             | 12 +++++
 src/authentic2/custom_user/apps.py            | 20 +++++---
 src/authentic2/models.py                      |  9 +++-
 src/authentic2/settings.py                    |  2 +
 .../templates/authentic2/accounts.html        | 18 ++++---
 .../templates/authentic2/accounts_edit.html   |  7 ++-
 src/authentic2/urls.py                        |  4 ++
 src/authentic2/utils.py                       | 51 +++++++++++++++++++
 8 files changed, 108 insertions(+), 15 deletions(-)
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 store_image
20 21

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

  
......
151 152
        'field_class': PhoneNumberField,
152 153
        'rest_framework_field_class': PhoneNumberDRFField,
153 154
    },
155
    {
156
        'label': _('image'),
157
        'name': 'image',
158
        'field_class': forms.ImageField,
159
        'serialize': store_image,
160
        'serialize_eval_args' : [
161
            "owner.uuid",
162
        ],
163
        'deserialize': lambda x: x,
164
        'rest_framework_field_class': serializers.ImageField,
165
    },
154 166
]
155 167

  
156 168

  
src/authentic2/custom_user/apps.py
10 10
        from django.db.models.signals import post_migrate
11 11

  
12 12
        post_migrate.connect(
13
            self.create_first_name_last_name_attributes,
13
            self.create_custom_attributes,
14 14
            sender=self)
15 15

  
16
    def create_first_name_last_name_attributes(self, app_config, verbosity=2, interactive=True,
16
    def create_custom_attributes(self, app_config, verbosity=2, interactive=True,
17 17
                                               using=DEFAULT_DB_ALIAS, **kwargs):
18 18
        from django.utils import translation
19 19
        from django.utils.translation import ugettext_lazy as _
......
50 50
                      'asked_on_registration': True,
51 51
                      'user_editable': True,
52 52
                      'user_visible': True})
53
        attrs['avatar_picture'], created = Attribute.objects.get_or_create(
54
            name='avatar_picture',
55
            defaults={'kind': 'image',
56
                      'label': _('Avatar picture'),
57
                      'required': False,
58
                      'asked_on_registration': False,
59
                      'user_editable': True,
60
                      'user_visible': True})
53 61

  
54
        serialize = get_kind('string').get('serialize')
55 62
        for user in User.objects.all():
56
            for attr_name in attrs:
63
            for at in attrs:
64
                serialize = get_kind(at.kind).get('serialize')
57 65
                av, created = AttributeValue.objects.get_or_create(
58 66
                    content_type=content_type,
59 67
                    object_id=user.id,
60
                    attribute=attrs[attr_name],
68
                    attribute=attrs[at],
61 69
                    defaults={
62 70
                        'multiple': False,
63 71
                        'verified': False,
64
                        'content': serialize(getattr(user, attr_name, None))
72
                        'content': serialize(getattr(user, at, None))
65 73
                    })
src/authentic2/models.py
225 225
                    av.verified = verified
226 226
                    av.save()
227 227
        else:
228
            content = serialize(value)
228
            if self.get_kind().get('serialize_eval_args'):
229
                serialize_args = list()
230
                for flat_arg in self.get_kind().get('serialize_eval_args', []):
231
                    serialize_args.append(eval(flat_arg))
232
                content = serialize(value, *serialize_args)
233
            else:
234
                content = serialize(value)
235

  
229 236
            av, created = AttributeValue.objects.get_or_create(
230 237
                    content_type=ContentType.objects.get_for_model(owner),
231 238
                    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 = []
src/authentic2/templates/authentic2/accounts.html
18 18
          {% for attribute in attributes %}
19 19
            <dt>{{ attribute.attribute.label|capfirst }}&nbsp;:</dt>
20 20
            <dd>
21
              {% if attribute.values|length == 1 %}
22
                {{ attribute.values.0 }}
21
              {% if attribute.attribute.kind == 'image' %}
22
                <img src="{{ attribute.values.0 }}">
23 23
              {% else %}
24
                <ul>
25
                  {% for value in attribute.values %}
26
                    <li>{{ value }}</li>
27
                  {% endfor %}
28
                </ul>
24
                {% if attribute.values|length == 1 %}
25
                  {{ attribute.values.0 }}
26
                {% else %}
27
                  <ul>
28
                    {% for value in attribute.values %}
29
                      <li>{{ value }}</li>
30
                    {% endfor %}
31
                  </ul>
32
                {% endif %}
29 33
              {% endif %}
30 34
            </dd>
31 35
          {% endfor %}
src/authentic2/templates/authentic2/accounts_edit.html
12 12
{% endblock %}
13 13

  
14 14
{% block content %}
15
  <form method="post">
15
    {% if form.is_multipart %}
16
      <form enctype="multipart/form-data" method="post">
17
    {% else %}
18
      <form method="post">
19
    {% endif %}
20

  
16 21
    {% csrf_token %}
17 22
    {{ form.as_p }}
18 23
    {% if form.instance and form.instance.id %}
src/authentic2/urls.py
44 44
    urlpatterns += [
45 45
        url(r'^static/(?P<path>.*)$', serve)
46 46
    ]
47
    urlpatterns += [
48
        url(r'^media/(?P<path>.*)$', 'django.views.static.serve', {
49
        'document_root': settings.MEDIA_ROOT})
50
    ]
47 51

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

  
12 15
from functools import wraps
13 16
from itertools import islice, chain, count
14 17

  
15 18
from importlib import import_module
19
from hashlib import md5
16 20

  
17 21
from django.conf import settings
18 22
from django.http import HttpResponseRedirect, HttpResponse
......
30 34
from django.template.loader import render_to_string, TemplateDoesNotExist
31 35
from django.core.mail import send_mail
32 36
from django.core import signing
37
from django.core.files.storage import default_storage
33 38
from django.core.urlresolvers import reverse, NoReverseMatch
34 39
from django.utils.formats import localize
35 40
from django.contrib import messages
......
1073 1078
        if ou_value is not None:
1074 1079
            return ou_value
1075 1080
    return default
1081

  
1082

  
1083
def store_image(file_wrapper, owner_uuid):
1084
    logger = logging.getLogger(__name__)
1085

  
1086
    digest = md5(file_wrapper.read())
1087
    image_uuid = digest.hexdigest()
1088
    image_format = file_wrapper.image.format
1089

  
1090
    image_folder = default_storage.path('avatars/{oid}'.format(
1091
        oid=owner_uuid))
1092

  
1093
    image_path = os.path.join(
1094
            image_folder,
1095
            "{uuid}.{ext}".format(uuid=image_uuid, ext=image_format))
1096

  
1097
    uri = os.path.join(settings.MEDIA_URL, 'avatars/{oid}/{uuid}.{ext}'.format(
1098
            oid=owner_uuid, uuid=image_uuid, ext=image_format))
1099

  
1100
    try:
1101
        if not os.path.exists(image_folder):
1102
            os.makedirs(image_folder)
1103

  
1104
        with open(image_path, 'wb') as f:
1105
            try:
1106
                fcntl.lockf(f, fcntl.LOCK_EX | fcntl.LOCK_NB)
1107
                with tempfile.NamedTemporaryFile(mode='wb', dir=image_folder, delete=False) as temp:
1108
                    try:
1109
                        file_wrapper.seek(0)
1110
                        temp.write(file_wrapper.read())
1111
                        temp.flush()
1112
                        os.rename(temp.name, image_path)
1113
                        pass
1114
                    except:
1115
                        logger.error("Could'nt store image to {}", file_path)
1116
                        os.unlink(temp.name)
1117
                    finally:
1118
                        fcntl.lockf(f, fcntl.LOCK_UN)
1119
            except:
1120
                logger.error("Couldn't hold exclusive lock for file {}".format(image_path))
1121
            finally:
1122
                fcntl.lockf(f, fcntl.LOCK_UN)
1123
    except IOError:
1124
        return
1125

  
1126
    return uri
1076
-