~homeworkprod/byceps

ref: 533662eefb314d54b168e5a46bc07c88b5f88be4 byceps/byceps/blueprints/site/user/avatar/views.py -rw-r--r-- 3.1 KiB
533662ee — Jochen Kupperschmidt Use Flask v2.0's `delete`/`get`/`patch`/`post` route shortcuts 2 months ago
                                                                                
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
"""
byceps.blueprints.site.user.avatar.views
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

:Copyright: 2006-2021 Jochen Kupperschmidt
:License: Revised BSD (see `LICENSE` file for details)
"""

from flask import abort, g, request
from flask_babel import gettext

from .....services.image import service as image_service
from .....services.user import service as user_service
from .....services.user_avatar import service as avatar_service
from .....signals import user_avatar as user_avatar_signals
from .....util.framework.blueprint import create_blueprint
from .....util.framework.flash import flash_notice, flash_success
from .....util.image.models import ImageType
from .....util.framework.templating import templated
from .....util.views import redirect_to, respond_no_content

from .forms import UpdateForm


blueprint = create_blueprint('user_avatar', __name__)


ALLOWED_IMAGE_TYPES = frozenset(
    [
        ImageType.jpeg,
        ImageType.png,
    ]
)


@blueprint.get('/me/avatar/update')
@templated
def update_form(erroneous_form=None):
    """Show a form to update the current user's avatar image."""
    _get_current_user_or_404()

    form = erroneous_form if erroneous_form else UpdateForm()

    image_type_names = image_service.get_image_type_names(ALLOWED_IMAGE_TYPES)

    return {
        'form': form,
        'allowed_types': image_type_names,
        'maximum_dimensions': avatar_service.MAXIMUM_DIMENSIONS,
    }


@blueprint.post('/me/avatar')
def update():
    """Update the current user's avatar image."""
    user = _get_current_user_or_404()

    # Make `InputRequired` work on `FileField`.
    form_fields = request.form.copy()
    if request.files:
        form_fields.update(request.files)

    form = UpdateForm(form_fields)

    if not form.validate():
        return update_form(form)

    image = request.files.get('image')

    _update(user.id, image)

    flash_success(gettext('Avatar image has been updated.'), icon='upload')
    user_avatar_signals.avatar_updated.send(None, user_id=user.id)

    return redirect_to('user_settings.view')


def _update(user_id, image):
    if not image or not image.filename:
        abort(400, 'No file to upload has been specified.')

    try:
        avatar_service.update_avatar_image(
            user_id, image.stream, ALLOWED_IMAGE_TYPES
        )
    except user_service.UserIdRejected as e:
        abort(404)
    except avatar_service.ImageTypeProhibited as e:
        abort(400, str(e))
    except FileExistsError:
        abort(409, 'File already exists, not overwriting.')


@blueprint.delete('/me/avatar')
@respond_no_content
def delete():
    """Remove the current user's avatar image."""
    user = _get_current_user_or_404()

    try:
        avatar_service.remove_avatar_image(user.id)
    except ValueError:
        # No avatar selected.
        # But that's ok, deletions should be idempotent.
        flash_notice(gettext('No avatar image is set that could be removed.'))
    else:
        flash_success(gettext('Avatar image has been removed.'))


def _get_current_user_or_404():
    user = g.user

    if not user.authenticated:
        abort(404)

    return user